home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / Sample Code / Printing Samples / Applications… / Exp. #9 (Inside Mac code) ƒ / Experiment no.9.c < prev    next >
Encoding:
Text File  |  1996-06-14  |  99.6 KB  |  3,888 lines  |  [TEXT/MPS ]

  1. // Experiment no.9
  2. //
  3. // Fast food code to check out various printing operations.
  4. //
  5. // This application contains routines that exercise nearly every part
  6. // of the QuickDraw GX printing API-- from handling the modified 'pdoc'
  7. // AppleEvents or properly servicing resume events, to adding a panel in
  8. // the "Page Setup" dialog or reading pages from a print file.  For the
  9. // most part, the code in this file is "ungroomed," but it's still useful
  10. // if you're trying to figure out how to take advantage of a particular
  11. // GX printing feature.
  12. //
  13. // All routines are listed in MPW's Mark menu, to make it easy to find the
  14. // code you're looking for.  For example, if you were trying to figure out
  15. // how to flatten a gxJob into your document's data fork, you'd go to the
  16. // routine listed as "MySaveJobInDataFork" in the Mark menu.
  17. //
  18. // If you don't see a marked routine that looks like what you're after, try
  19. // searching for the specific GX routine you're interested in.  Some routines
  20. // in this file, (like the saving routines), do a lot more than their names
  21. // may imply.  And, note that not all of the routines in this file are used
  22. // by the built application.  For example, none of the routines which get
  23. // format mappings are used, since they don't do anything visible.  Also,
  24. // there are 4 different print routines, 3 different open routines, and 2
  25. // different saving routines.  Only one of each is used by the built app.
  26. // If you change which ones are used, make sure that the opening and saving
  27. // routines agree with each other.  If the open routine expects to load a
  28. // saved job from a document's data fork, make sure that you aren't using
  29. // the routine which saves the job in the resource fork.
  30. //
  31. // This application has been thrown together very roughly, and is meant to
  32. // be a functioning "container" for the print code snippets that an application
  33. // developer is most likely to want.  The Inside Mac printing samples were
  34. // written in this application, so much of what appears here also appears in
  35. // Inside Mac.
  36. //
  37. //  4/26/93 - dmh - Thrown on the grill.
  38. //  9/10/93 - dmh - Updated for b2.
  39. //                    Neutralized some nasty bugs.
  40. // 12/18/93 - dmh - Updated for b3.
  41. //  2/03/94 - dmh - Made "square resolution" in
  42. //                    MyGetFormatDeviceResolution really square.
  43. //  3/22/94 - dmh - Added page range code (only enable for f2c1.2 or later!!).
  44. //  3/22/94 - dmh - Added "print one copy" code.
  45. //  3/22/94 - dmh - Added code to retrieve the formatting printers profiel and colorSpace.
  46. //    3/22/94 - dmh - Cleaned up(?) the Mark menu.
  47. //    3/22/94 - dmh - Updated for b4.
  48. //    3/24/94 - dmh - general cleanup and debugging.
  49. //    5/3/94     - dmh - …more of the same for f2.
  50. //    7/13/94 - dmh - Enabled printer resolution code.
  51. //    8/24/94 - dmh - Universalized.
  52. //    6/14/96 - cn  - Updated to support Universal Interfaces 2.1.
  53. //
  54.  
  55. #include "Experiment no.9.h"
  56. #include "GXExceptions.h"
  57.  
  58.  
  59. QDGlobals            qd;
  60.  
  61. Boolean                gQuitting;            // Quitting?
  62. MyDocumentRec        myDocument;            // Our document.
  63. short                gAppResRefNum;        // Our application's resource file refNum.
  64. Boolean                gInPrintDialog;        // Currently in a print dialog?
  65. RgnHandle            gCursorRgn;            // Mouse region used by WaitNextEvent.
  66.  
  67. // This routine initializes everything for our application.
  68.  
  69. OSErr MyInitializeApp()
  70. {
  71.     OSErr        err = noErr;
  72.     Handle        menuBar;
  73.  
  74.     gQuitting = false;
  75.     gInPrintDialog = false;
  76.  
  77.     InitGraf((Ptr) &qd.thePort);
  78.     InitFonts();
  79.     InitWindows();
  80.     InitMenus();
  81.     TEInit();
  82.     InitDialogs(nil);
  83.     InitCursor();
  84.     FlushEvents(everyEvent, 0);
  85.  
  86.     gAppResRefNum = CurResFile();
  87.     gCursorRgn = NewRgn();
  88.  
  89.  
  90. // Create and set up the menubar.
  91.  
  92.     menuBar = GetNewMBar(r_menuBar);
  93.     SetMenuBar(menuBar);
  94.     DisposHandle(menuBar);
  95.     AddResMenu(GetMHandle(mApple), 'DRVR');
  96.     MyAdjustMenus();
  97.     DrawMenuBar();
  98.  
  99.     MyAEInstallation();
  100.  
  101.     return err;
  102. }
  103.  
  104.  
  105. // This routine installs our core AppleEvent handlers.
  106.  
  107. void MyAEInstallation()
  108. {
  109.     AEInstallEventHandler(kCoreEventClass,
  110.                           kAEOpenApplication,
  111.                           NewAEEventHandlerProc(MyHandleOAPP),
  112.                           0, false);
  113.  
  114.     AEInstallEventHandler(kCoreEventClass,
  115.                           kAEQuitApplication,
  116.                           NewAEEventHandlerProc(MyHandleQUIT),
  117.                           0, false);
  118.  
  119.     AEInstallEventHandler(kCoreEventClass,
  120.                           kAEOpenDocuments,
  121.                           NewAEEventHandlerProc(MyHandleODOC),
  122.                           0, false);
  123.  
  124.     AEInstallEventHandler(kCoreEventClass,
  125.                           kAEPrintDocuments,
  126.                           NewAEEventHandlerProc(MyHandlePDOC),
  127.                           0, false);
  128. }
  129.  
  130.  
  131. // This is the "open application" AppleEvent handler.  We don't
  132. // do anything more than check out the message.
  133.  
  134. pascal OSErr MyHandleOAPP(AppleEvent *theAppleEvent, AppleEvent *reply, long myRefCon)
  135. {
  136.  
  137. #pragma unused (reply, myRefCon)
  138.     
  139.     return MyCheckAEParams(theAppleEvent);
  140. }
  141.  
  142.  
  143. // This is the "quit" AppleEvent handler.  Set the gQuitting and
  144. // the event loop will do the rest.
  145.  
  146. pascal OSErr MyHandleQUIT(AppleEvent *theAppleEvent, AppleEvent *reply, long myRefCon)
  147. {
  148.     OSErr    err;
  149.  
  150. #pragma unused (reply, myRefCon)
  151.  
  152.     err = MyCheckAEParams(theAppleEvent);
  153.     if (err) return err;
  154.  
  155.     gQuitting = true;
  156.     return noErr;
  157. }
  158.  
  159.  
  160. // This is the "open document" AppleEvent handler.
  161.  
  162. pascal OSErr MyHandleODOC(AppleEvent *theAppleEvent, AppleEvent *reply, long myRefCon)
  163. {
  164.     OSErr            err;
  165.     AEDescList        docList;
  166.     FSSpec            myFSS;
  167.     AEKeyword        theKeyword;
  168.     DescType        typeCode;
  169.     Size            actualSize;
  170.  
  171. #pragma unused (reply, myRefCon)
  172.  
  173. // Get our doc list.
  174.  
  175.     err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList);
  176.     if (err) return err;
  177.  
  178.     err = MyCheckAEParams(theAppleEvent);
  179.     if (err) return err;
  180.     
  181.  
  182. // Open the first entry in the document list.  This app only handles one
  183. // document at a time, so if we are trying to open a second, don't.
  184.  
  185.     err = AEGetNthPtr(&docList, 1, typeFSS, &theKeyword, &typeCode,
  186.                       (Ptr) &myFSS, sizeof(FSSpec), &actualSize);
  187.  
  188.     AEDisposeDesc(&docList);
  189.  
  190.     if (err || (FrontWindow() != nil)) return err;
  191.  
  192.     err = MyNewDocument("\pUntitled", &myDocument);
  193.  
  194.     if (err == noErr)
  195.     {
  196.         err = MyFSOpenDocument(&myDocument, &myFSS);
  197.  
  198.         if (err == noErr)
  199.             ShowWindow(myDocument.documentWindow);
  200.     }
  201.     
  202.     if (err != noErr) MyCloseDocument(&myDocument);
  203.  
  204.     return err;
  205. }
  206.  
  207.  
  208. // This is our "print document" AppleEvent handler.  It handles files printed
  209. // with the Finder's 'Print' command, as well as those dragged to desktop
  210. // printers.
  211.  
  212. pascal OSErr MyHandlePDOC(AppleEvent *theAppleEvent, AppleEvent *reply, long myRefCon)
  213. {
  214.     OSErr            err;
  215.     AEDescList        docList, dtpList;
  216.     FSSpec            myFSS, dtpFSS;
  217.     long            itemsInList, i;
  218.     AEKeyword        theKeyword;
  219.     DescType        typeCode;
  220.     Boolean            draggedToDTP = false;
  221.     Size            actualSize;
  222.  
  223. #pragma unused (reply, myRefCon)
  224.  
  225. // Get our document list.
  226.  
  227.     err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList);
  228.     if (err) return err;
  229.  
  230.  
  231. // See if the document was dragged to a desktop printer.
  232.  
  233.     err = AEGetAttributeDesc(theAppleEvent, keyOptionalKeywordAttr, typeAEList, &dtpList);
  234.     if (err == noErr) draggedToDTP = true;
  235.  
  236.  
  237. // Make sure we've accounted for all of the parameters passed, and count the
  238. // number of documents passed in.
  239.  
  240.     err = MyCheckAEParams(theAppleEvent);
  241.     if (err) return err;
  242.     
  243.     err = AECountItems(&docList, &itemsInList);
  244.     if (err) return err;
  245.  
  246.  
  247. // If we dragged to a desktop printer, get the name of the desktop printer
  248. // and then throw away the description list for it.
  249.  
  250.     if (draggedToDTP)
  251.     {
  252.         err = AEGetNthPtr(&dtpList, 1, typeFSS, &theKeyword, &typeCode,
  253.                           (Ptr) &dtpFSS, sizeof(FSSpec), &actualSize);
  254.     
  255.         AEDisposeDesc(&dtpList);
  256.     }
  257.  
  258. // For each entry in the document list, load it, print it, and close it.
  259.  
  260.     for (i = 1; i<= itemsInList, err == noErr; i++)
  261.     {
  262.         err = AEGetNthPtr(&docList, i, typeFSS, &theKeyword, &typeCode,
  263.                           (Ptr) &myFSS, sizeof(FSSpec), &actualSize);
  264.  
  265.         if (err == noErr)
  266.         {
  267.  
  268. // Load the document.
  269.  
  270.             err = MyNewDocument("\p", &myDocument);
  271.     
  272.             if (err == noErr)
  273.             {
  274.                 err = MyFSOpenDocument(&myDocument, &myFSS);
  275.  
  276.  
  277. // If we dragged to a desktop printer, select that as the output printer for
  278. // each job and only print one copy.  Otherwise, present the dialogs so that
  279. // the user can set things up.
  280.  
  281.                 if (err == noErr)
  282.                 {
  283.                     if (draggedToDTP)
  284.                     {
  285.                         GXSelectJobOutputPrinter(myDocument.documentJob, dtpFSS.name);
  286.                         err = MyPrintOneCopy(&myDocument);
  287.                     }
  288.                     else
  289.                         err = MyPrintDocument(&myDocument);
  290.                 }
  291.  
  292. // Close the document once it's printed.
  293.  
  294.                 MyCloseDocument(&myDocument);
  295.             }
  296.         }
  297.     }
  298.  
  299. // When we're all done throw away the document list.
  300.  
  301.     AEDisposeDesc(&docList);
  302.     return err;
  303. }
  304.  
  305.  
  306. // MyCheckAEParams - This routine is used to make sure we've
  307. // received all the parameters for an AppleEvent.  If so, we
  308. // return noErr, otherwise we indicate that the event wasn't
  309. // handled completely.
  310.  
  311. OSErr MyCheckAEParams(AppleEvent *theAppleEvent)
  312. {
  313.     OSErr        err;
  314.     DescType    typeCode;
  315.     Size        actualSize;
  316.     
  317.     err = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr,
  318.                             typeWildCard, &typeCode, nil, 0, &actualSize);
  319.  
  320.     if (err == errAEDescNotFound) return noErr;
  321.     if (err == noErr) return errAEEventNotHandled;
  322.     
  323.     return err;
  324. }
  325.  
  326.  
  327. // Our event loop routine.
  328.  
  329. void MyEventLoop()
  330. {
  331.     Boolean        gotEvent;
  332.     EventRecord    event;
  333.     long        sleepTime;
  334.     
  335. // While not quitting, repeatedly get and dispatch events.  Sleep
  336. // an appropriate amount whether we're running in the foreground
  337. // or background.  Every time through we unload all our segments.
  338. // They won't actually be purged unless we need the memory.
  339.  
  340.     while (!gQuitting)
  341.     {
  342.         sleepTime = GetDblTime();
  343.         gotEvent = WaitNextEvent(everyEvent, &event, sleepTime, gCursorRgn);
  344.  
  345.         if (gotEvent)
  346.             MyDoEvent(&event);
  347.     }
  348. }
  349.  
  350.  
  351. // This routine handles whatever events come our way.
  352.  
  353. OSErr MyDoEvent(EventRecord *event)
  354. {
  355.     OSErr            err = noErr;
  356.     short            windowPart;
  357.     WindowPtr        window;
  358.     char            key;
  359.     Point            mountPoint;
  360.     Rect            dragRect;
  361.     RgnHandle        grayRgn;
  362.     WindowPtr        curWindow;
  363.     MyDocumentPtr    windowDoc;
  364.  
  365. // Set up a rectangle to use for dragging windows around.  Then,
  366. // handle any events.
  367.  
  368.     grayRgn = GetGrayRgn();
  369.     dragRect = (*grayRgn)->rgnBBox;
  370.     
  371.     switch (event->what)
  372.     {
  373.         case mouseDown:
  374.             windowPart = FindWindow(event->where, &window);
  375.             switch (windowPart)
  376.             {
  377.                 case inMenuBar:
  378.                     MyAdjustMenus();
  379.                     MyDoMenuCommand(MenuSelect(event->where));
  380.                     break;
  381.                 
  382.                 case inContent:
  383.                     if (window != FrontWindow())
  384.                         SelectWindow(window);
  385.                     break;
  386.                     
  387.                 case inDrag:
  388.                     DragWindow(window, event->where, &dragRect);
  389.                     break;
  390.                     
  391.                 case inGoAway:
  392.                     if (TrackGoAway(window, event->where))
  393.                     {
  394.                         err = MyCloseDocument(&myDocument);
  395.                         if (err)
  396.                         {
  397.                             Str255    pStr;
  398.                             
  399.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyCloseDocument!", err);
  400.                             MyDisplayInfo(pStr);
  401.                         }
  402.                     }
  403.                     break;
  404.             }
  405.             break;
  406.                     
  407.         case mouseMovedMessage:
  408.             DisposeRgn(gCursorRgn);    /* get rid of old region */
  409.             gCursorRgn = NewRgn();
  410.             SetRectRgn(gCursorRgn, -32768, -32768, 32766, 32766);
  411.             break;
  412.  
  413.         case keyDown:
  414.         case autoKey:
  415.             key = event->message & charCodeMask;
  416.             if (event->modifiers & cmdKey)
  417.                 if (event->what == keyDown)
  418.                 {
  419.                     MyAdjustMenus();
  420.                     MyDoMenuCommand(MenuKey(key));
  421.                 }
  422.             break;
  423.  
  424.         case updateEvt:
  425.             MyWindowUpdate((WindowPtr) event->message);
  426.             break;
  427.         
  428.         case diskEvt:
  429.             if ((event->message >> 16) != noErr)
  430.             {
  431.                 mountPoint.h = 100;
  432.                 mountPoint.v = 100;
  433.                 err = DIBadMount(mountPoint, event->message);
  434.             }
  435.             break;
  436.             
  437.         case osEvt:
  438.             switch ((event->message >> 24) & 0x0FF)
  439.             {
  440.                 case suspendResumeMessage:
  441.                     
  442.                     SetCursor(&qd.arrow);
  443.  
  444. // Suspend event:
  445. //
  446. // On a suspend event, just coerce the scrap. 
  447.                 
  448.                     if ((event->message & resumeFlag) == 0)
  449.                     {
  450.                         ZeroScrap();
  451.                         TEToScrap();
  452.                     }
  453.                     else
  454.                     {
  455.  
  456. // Resume event:
  457. //
  458. // On a resume event, we need to call UpdateJob on all of our documents'
  459. // jobs.  This is important because the user may have just changed
  460. // something which affects our jobs (like the size of the paper in the
  461. // printer).
  462. //
  463. // Since our application stores our document pointers in the refCon fields
  464. // of our documents' windows, we just loop through every one of our windows,
  465. // extract our document pointers and update the associated jobs.
  466.  
  467.                         if (event->message & convertClipboardFlag)
  468.                             TEFromScrap();
  469.  
  470.                         curWindow = FrontWindow();
  471.                         
  472.                         while (curWindow != nil)
  473.                         {
  474.                             if (((WindowPeek) curWindow)->windowKind == userKind)
  475.                             {
  476.                                 windowDoc = (MyDocumentPtr) GetWRefCon(curWindow);
  477.                                 GXUpdateJob(windowDoc->documentJob);
  478.                             }
  479.                             
  480.                             curWindow = (WindowPtr) ((WindowPeek) curWindow)->nextWindow;
  481.                         }
  482.                     }
  483.                     break;
  484.             }
  485.             break;
  486.                 
  487.         case kHighLevelEvent:
  488.             AEProcessAppleEvent(event);
  489.             break;
  490.     }
  491.     
  492.     return err;
  493. }
  494.  
  495.  
  496. // This routine handles enabling and disabling menu items as
  497. // required by the current context.
  498.  
  499. void MyAdjustMenus()
  500. {
  501.     WindowPtr        wp;
  502.     MenuHandle        fileMenu, editMenu, testMenu;
  503.     MyDocumentPtr    myDocument;
  504.     Boolean            docOpen, hasPages, onFirstPage, onLastPage, maxPages, neverSaved;
  505.     
  506.     if (gInPrintDialog) return;
  507.  
  508.     editMenu = GetMHandle(mEdit);
  509.     fileMenu = GetMHandle(mFile);
  510.     testMenu = GetMHandle(mTest);
  511.  
  512.     EnableItem(fileMenu,  kQuit);
  513.     EnableItem(testMenu,  kGetFileNumPages);
  514.  
  515.  
  516. // If we have a window open, we enable certain menu items,
  517. // otherwise we don't.
  518.  
  519.     wp = FrontWindow();
  520.  
  521.     if (((WindowPeek) wp)->windowKind != userKind)
  522.         wp = nil;
  523.  
  524.     docOpen = (wp != nil);
  525.  
  526.     if (!docOpen)
  527.     {
  528.         EnableItem(fileMenu,  kNew);
  529.         EnableItem(fileMenu,  kOpen);
  530.         DisableItem(fileMenu, kClose);
  531.         DisableItem(fileMenu, kSave);
  532.         DisableItem(fileMenu, kSaveAs);
  533.         DisableItem(fileMenu, kInsertPage);
  534.         DisableItem(fileMenu, kDeletePage);
  535.         DisableItem(fileMenu, kPrint);
  536.         DisableItem(fileMenu, kPrintOne);
  537.         DisableItem(fileMenu, kPageSetup);
  538.         DisableItem(fileMenu, kDocSetup);
  539.         EnableItem(fileMenu,  kQuit);
  540.         DisableItem(testMenu, kAheadPage);
  541.         DisableItem(testMenu, kBackPage);
  542.         DisableItem(testMenu, kAddForm);
  543.         DisableItem(testMenu, kRemoveForm);
  544.         DisableItem(testMenu, kApplyAboveFormat);
  545.         DisableItem(testMenu, kGetCopiesInfo);
  546.         DisableItem(testMenu, kShowJobPrinterInfo);
  547.         DisableItem(testMenu, kJobRefConTest);
  548.         DisableItem(testMenu, kReadFilePage);
  549.         DisableItem(testMenu, kGetPaperTypeName);
  550.         DisableItem(testMenu, kGetPaperDimensions);
  551.         DisableItem(testMenu, kGetAllPaperTypeInfo);
  552.         DisableItem(testMenu, kShowPrinterResolution);
  553.     }
  554.     else
  555.     {
  556.         DisableItem(fileMenu, kNew);
  557.         DisableItem(fileMenu, kOpen);
  558.         EnableItem(fileMenu,  kClose);
  559.         EnableItem(fileMenu,  kDocSetup);
  560.         EnableItem(testMenu,  kGetCopiesInfo);
  561.         EnableItem(testMenu,  kShowJobPrinterInfo);
  562.         EnableItem(testMenu,  kJobRefConTest);
  563.         EnableItem(testMenu,  kShowPrinterResolution);
  564.  
  565.         myDocument = (MyDocumentPtr) GetWRefCon(wp);
  566.     
  567.         hasPages = (myDocument->numPages != 0);
  568.         onFirstPage = (myDocument->curPage == 1);
  569.         onLastPage = (myDocument->curPage == myDocument->numPages);
  570.         maxPages = (myDocument->numPages == kMaxPages);
  571.         neverSaved = (myDocument->documentFSSpec.name[0] == 0);
  572.  
  573.         if (neverSaved || !hasPages)
  574.             DisableItem(fileMenu, kSave);
  575.         else
  576.             EnableItem(fileMenu, kSave);
  577.  
  578.         if (!maxPages)
  579.             EnableItem(fileMenu, kInsertPage);
  580.         else
  581.             DisableItem(fileMenu, kInsertPage);
  582.  
  583.         if (hasPages)
  584.         {
  585.             EnableItem(fileMenu, kSaveAs);
  586.             EnableItem(fileMenu, kDeletePage);
  587.             EnableItem(fileMenu, kPrintOne);
  588.             EnableItem(fileMenu, kPageSetup);
  589.             EnableItem(fileMenu, kPrint);
  590.             EnableItem(testMenu, kAddForm);
  591.             EnableItem(testMenu, kRemoveForm);
  592.             EnableItem(testMenu, kReadFilePage);
  593.             EnableItem(testMenu, kGetPaperTypeName);
  594.             EnableItem(testMenu, kGetPaperDimensions);
  595.             EnableItem(testMenu, kGetAllPaperTypeInfo);
  596.         }
  597.         else
  598.         {
  599.             DisableItem(fileMenu, kSaveAs);
  600.             DisableItem(fileMenu, kDeletePage);
  601.             DisableItem(fileMenu, kPrintOne);
  602.             DisableItem(fileMenu, kPageSetup);
  603.             DisableItem(fileMenu, kPrint);
  604.             DisableItem(testMenu, kAddForm);
  605.             DisableItem(testMenu, kRemoveForm);
  606.             DisableItem(testMenu, kReadFilePage);
  607.             DisableItem(testMenu, kGetPaperTypeName);
  608.             DisableItem(testMenu, kGetPaperDimensions);
  609.             DisableItem(testMenu, kGetAllPaperTypeInfo);
  610.         }
  611.  
  612.         if (hasPages && !onLastPage)
  613.             EnableItem(testMenu, kAheadPage);
  614.         else
  615.             DisableItem(testMenu, kAheadPage);
  616.  
  617.         if (hasPages && !onFirstPage)
  618.             EnableItem(testMenu, kBackPage);
  619.         else
  620.             DisableItem(testMenu, kBackPage);
  621.  
  622.         if (!onLastPage && (myDocument->numPages > 1))
  623.             EnableItem(testMenu, kApplyAboveFormat);
  624.         else
  625.             DisableItem(testMenu, kApplyAboveFormat);
  626.     }
  627. }
  628.  
  629.  
  630. // This routine handles our menu command dispatching.
  631.  
  632. void MyDoMenuCommand(long menuResult)
  633. {
  634.     short                menuID;
  635.     short                menuItem;
  636.     long                curPage;
  637.     Str255                daName;
  638.     OSErr                err = noErr;
  639.     WindowPtr            aWindow;
  640.     MyDocumentPtr        aDocument;
  641.  
  642. // Get the selected menu's ID, item and MenuHandle.
  643.  
  644.     menuID = menuResult >>16;
  645.     menuItem = menuResult & 0xFFFF;
  646.  
  647.     switch (menuID)
  648.     {
  649.         case mApple:
  650.             switch (menuItem)
  651.             {
  652.                 case kAbout:                // Display About box.
  653.                     MyDisplayAbout();
  654.                     break;
  655.                 
  656.                 default:                    // Handle DAs.
  657.                     
  658.                     GetItem(GetMHandle(mApple), menuItem, daName);
  659.                     OpenDeskAcc(daName);
  660.                     break;
  661.             }
  662.             break;
  663.             
  664.             case mFile:
  665.                 switch (menuItem)
  666.                 {
  667.                     case kOpen:                // Open a document.
  668.                         err = MyNewDocument("\pUntitled", &myDocument);
  669.                         if (!err)
  670.                         {
  671.                             err = MyOpenDocument(&myDocument);
  672.             //                err = MyOpenDocument2(&myDocument);
  673.                             if (err)
  674.                             {
  675.                                 Str255    pStr;
  676.                                 
  677.                                 MyCloseDocument(&myDocument);
  678.                                 pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyOpenDocument!", err);
  679.                                 MyDisplayInfo(pStr);
  680.                             }
  681.                             else
  682.                                 ShowWindow(myDocument.documentWindow);
  683.  
  684.                         }
  685.                         else
  686.                         {
  687.                             Str255    pStr;
  688.                             
  689.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyNewDocument!", err);
  690.                             MyDisplayInfo(pStr);
  691.                         }
  692.                         break;
  693.  
  694.                     case kNew:                // Create a new document.
  695.                         err = MyNewDocument("\pUntitled", &myDocument);
  696.                         if (err)
  697.                         {
  698.                             Str255    pStr;
  699.                             
  700.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyNewDocument!", err);
  701.                             MyDisplayInfo(pStr);
  702.                         }
  703.                         else
  704.                             ShowWindow(myDocument.documentWindow);
  705.                         break;
  706.                     
  707.                     case kClose:            // Close a document.
  708.                         err = MyCloseDocument(&myDocument);
  709.                         if (err)
  710.                         {
  711.                             Str255    pStr;
  712.                             
  713.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyCloseDocument!", err);
  714.                             MyDisplayInfo(pStr);
  715.                         }
  716.                         break;
  717.                     
  718.                     case kSave:                // Save a document to its original file.
  719.                         err = MySaveDocument(&myDocument, false);
  720.             //            err = MySaveDocument2(&myDocument, false);
  721.                         if (err)
  722.                         {
  723.                             Str255    pStr;
  724.                             
  725.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MySaveDocument!", err);
  726.                             MyDisplayInfo(pStr);
  727.                         }
  728.                         break;
  729.                     
  730.                     case kSaveAs:            // Save a document to a new file.
  731.                         err = MySaveDocument(&myDocument, true);
  732.             //            err = MySaveDocument2(&myDocument, true);
  733.                         if (err)
  734.                         {
  735.                             Str255    pStr;
  736.                             
  737.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MySaveDocument!", err);
  738.                             MyDisplayInfo(pStr);
  739.                         }
  740.                         break;
  741.  
  742.                     case kInsertPage:         // Insert a page.
  743.                         err = MyInsertPage(&myDocument);
  744.                         if (err)
  745.                         {
  746.                             Str255    pStr;
  747.                             
  748.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyInsertPage!", err);
  749.                             MyDisplayInfo(pStr);
  750.                         }
  751.                         break;
  752.  
  753.                     case kDeletePage:         // Delete a page.
  754.                         err = MyDeletePage(&myDocument);
  755.                         if (err)
  756.                         {
  757.                             Str255    pStr;
  758.                             
  759.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyDeletePage!", err);
  760.                             MyDisplayInfo(pStr);
  761.                         }
  762.                         break;
  763.  
  764.                     case kPageSetup:        // Do a Page Setup.
  765.  
  766.                         err = MyPageFormatDialog(&myDocument);
  767.                         if (err)
  768.                         {
  769.                             Str255    pStr;
  770.                             
  771.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyPageFormatDialog!", err);
  772.                             MyDisplayInfo(pStr);
  773.                         }
  774.                         break;
  775.                                                 
  776.                     case kDocSetup:            // Do Document Setup.
  777.                         err = MyFormatDialog(&myDocument);
  778.                         if (err)
  779.                         {
  780.                             Str255    pStr;
  781.                             
  782.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyFormatDialog!", err);
  783.                             MyDisplayInfo(pStr);
  784.                         }
  785.                         break;
  786.  
  787.                     case kPrintOne:            // Print one.
  788.                         err = MyPrintOneCopy(&myDocument);
  789.                         if (err)
  790.                         {
  791.                             Str255    pStr;
  792.                             
  793.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyPrintOneCopy!", err);
  794.                             MyDisplayInfo(pStr);
  795.                         }
  796.                         break;
  797.  
  798.  
  799.                     case kPrint:            // Print a document.
  800.                         err = MyPrintDialog(&myDocument);
  801.                         if (err)
  802.                         {
  803.                             Str255    pStr;
  804.                             
  805.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyPrintDialog!", err);
  806.                             MyDisplayInfo(pStr);
  807.                         }
  808.                         break;
  809.  
  810.                     case kQuit:                // Quit the application.
  811.                         gQuitting = true;
  812.                         while (aWindow = FrontWindow())
  813.                         {
  814.                             aDocument = (MyDocumentPtr) GetWRefCon(aWindow);
  815.                             MyCloseDocument(&myDocument);
  816.                         }
  817.  
  818.                         break;
  819.                 }
  820.                 break;
  821.  
  822.         case mTest:
  823.             switch (menuItem)
  824.             {
  825.                 case kAheadPage:            // Go ahead a page.
  826.                     MyAheadPage(FrontWindow());
  827.                     break;
  828.                 
  829.                 case kBackPage:                // Go back a page.
  830.                     MyBackPage(FrontWindow());
  831.                     break;
  832.                 
  833.                 case kApplyAboveFormat:        // Apply format from page above this one (wrap to page 1).
  834.                     curPage = myDocument.curPage;
  835.  
  836.                     if (curPage == myDocument.numPages)
  837.                         curPage = 0;
  838.  
  839.                     err = MyApplyPageFormat(&myDocument, myDocument.pageFormat[curPage]);
  840.                     if (err)
  841.                     {
  842.                         Str255    pStr;
  843.                         
  844.                         pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyApplyPageFormat!", err);
  845.                         MyDisplayInfo(pStr);
  846.                     }
  847.                     break;
  848.                 
  849.                 case kAddForm:                // Add form to format.
  850.                     err = MyAddFormatForm(&myDocument);
  851.                     if (err)
  852.                     {
  853.                         Str255    pStr;
  854.                         
  855.                         pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyAddFormatForm!", err);
  856.                         MyDisplayInfo(pStr);
  857.                     }
  858.                     break;
  859.                 
  860.                 case kRemoveForm:            // Remove form from format.
  861.                     err = MyRemoveFormatForm(&myDocument);
  862.                     if (err)
  863.                     {
  864.                         Str255    pStr;
  865.                         
  866.                         pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyRemoveFormatForm!", err);
  867.                         MyDisplayInfo(pStr);
  868.                     }
  869.                     break;
  870.                     
  871.                 case kGetCopiesInfo:            // Get the number of copies stored in a job.
  872.                     {
  873.                         short    numCopies;
  874.  
  875.                         err = MyGetJobCopies(&myDocument, &numCopies);
  876.                         if (err)
  877.                         {
  878.                             Str255    pStr;
  879.                             
  880.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyGetJobCopies!", err);
  881.                             MyDisplayInfo(pStr);
  882.                         }
  883.                         else
  884.                         {
  885.                             Str255    pStr;
  886.                             
  887.                             pStr[0] = sprintf((char *) &pStr[1], "%s %i %s",
  888.                                               "This job will print",
  889.                                               numCopies, "copies.");
  890.                             MyDisplayInfo(pStr);
  891.                         }
  892.                     }
  893.                     break;
  894.                     
  895.                 case kGetFileNumPages:        // Get the number of pages stored in a spool file.
  896.                     {
  897.                         long                numPages;
  898.                         StandardFileReply    sfReply;
  899.                         SFTypeList            typeList;
  900.  
  901.                         typeList[0] = kPrintFileType1;
  902.                         typeList[1] = kPrintFileType2;
  903.                         typeList[2] = kPrintFileType3;
  904.                         typeList[3] = kPrintFileType4;
  905.  
  906.                         StandardGetFile(nil, 4, typeList, &sfReply);
  907.  
  908.                         if (!sfReply.sfGood) break;
  909.  
  910.                         err = MyGetPrintFilePages(&sfReply.sfFile, &numPages);
  911.                         if (err)
  912.                         {
  913.                             Str255    pStr;
  914.                             
  915.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyGetPrintFilePages!", err);
  916.                             MyDisplayInfo(pStr);
  917.                         }
  918.                         else
  919.                         {
  920.                             Str255    pStr;
  921.                             
  922.                             pStr[0] = sprintf((char *) &pStr[1], "%s %i %s",
  923.                                               "This file contains",
  924.                                               numPages, "pages.");
  925.                             MyDisplayInfo(pStr);
  926.                         }
  927.                     }
  928.                     break;
  929.                     
  930.                 case kShowJobPrinterInfo:        // Show the destination printer name, etc.
  931.                     err = MyShowJobPrinterInfo(&myDocument);
  932.                     if (err)
  933.                     {
  934.                         Str255    pStr;
  935.                         
  936.                         pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyShowJobPrinterInfo!", err);
  937.                         MyDisplayInfo(pStr);
  938.                     }
  939.                     break;
  940.                     
  941.                 case kJobRefConTest:        // Perform our Set/GXGetJobRefCon test.
  942.                     err = MyJobRefConTest(&myDocument);
  943.  
  944.                     if (err)
  945.                     {
  946.                         Str255    pStr;
  947.                         
  948.                         pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyJobRefConTest!", err);
  949.                         MyDisplayInfo(pStr);
  950.                     }
  951.                     break;
  952.                     
  953.                 case kReadFilePage:        // Replace the current page with page 1 from a print file.
  954.                     {
  955.                         StandardFileReply    sfReply;
  956.                         SFTypeList            typeList;
  957.                         gxShape                pgShape;
  958.                         gxFormat            pgFormat;
  959.                         
  960.                         typeList[0] = kPrintFileType1;
  961.                         typeList[1] = kPrintFileType2;
  962.                         typeList[2] = kPrintFileType3;
  963.                         typeList[3] = kPrintFileType4;
  964.  
  965.                         StandardGetFile(nil, 4, typeList, &sfReply);
  966.  
  967.                         if (!sfReply.sfGood) break;
  968.  
  969.                         err = MyReadPrintFilePage(&myDocument, &sfReply.sfFile, 1, &pgFormat, &pgShape);
  970.                         if (err)
  971.                         {
  972.                             Str255    pStr;
  973.                             
  974.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyReadPrintFilePage!", err);
  975.                             MyDisplayInfo(pStr);
  976.                         }
  977.                         else
  978.                         {
  979.                             if (myDocument.numPages != 0)
  980.                             {
  981.                                 if (myDocument.pageFormat[myDocument.curPage -1] != nil)
  982.                                     GXDisposeFormat(myDocument.pageFormat[myDocument.curPage -1]);
  983.     
  984.                                 GXDisposeShape(myDocument.documentPage[myDocument.curPage -1]);
  985.                             }
  986.             
  987.                             myDocument.pageFormat[myDocument.curPage -1] = pgFormat;
  988.                             myDocument.documentPage[myDocument.curPage -1] = pgShape;
  989.                             if (myDocument.numPages == 0)
  990.                             {
  991.                                 myDocument.curPage =
  992.                                 myDocument.numPages = 1;
  993.                             }
  994.                             
  995.                             InvalRect(&(myDocument.documentWindow)->portRect);
  996.                         }
  997.                     }
  998.                     break;
  999.                     
  1000.                 case kGetPaperTypeName:        // Gets the current page's paper type.
  1001.                     {
  1002.                         Str255    pStr;
  1003.  
  1004.                         err = MyGetPaperTypeName(&myDocument, pStr);
  1005.                         if (err)
  1006.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyGetPaperTypeName!", err);
  1007.                         
  1008.                         MyDisplayInfo(pStr);
  1009.                         break;
  1010.                     }
  1011.                     
  1012.                 case kGetPaperDimensions:        // Gets the current page's paper type dimensions.
  1013.                     {
  1014.                         gxRectangle    pageBounds, paperBounds;
  1015.                         Str255        pStr;
  1016.  
  1017.                         err = MyGetPaperTypeDims(&myDocument, &pageBounds, &paperBounds);
  1018.  
  1019.                         if (err)
  1020.                             pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyGetPaperTypeDims!", err);
  1021.                         else
  1022.                             pStr[0] = sprintf((char *) &pStr[1], "%s %i, %i, %i, %i.  %s %i, %i, %i, %i.",
  1023.                                               "pageBounds =",
  1024.                                               pageBounds.top >>16,
  1025.                                               pageBounds.left >>16,
  1026.                                               pageBounds.bottom >>16,
  1027.                                               pageBounds.right >>16,
  1028.                                               "paperBounds =",
  1029.                                               paperBounds.top >>16,
  1030.                                               paperBounds.left >>16,
  1031.                                               paperBounds.bottom >>16,
  1032.                                               paperBounds.right >>16);
  1033.  
  1034.                         MyDisplayInfo(pStr);
  1035.                         break;
  1036.                     }
  1037.                     
  1038.                 case kGetAllPaperTypeInfo:        // Gets all names and dimensions of a job's paperType.
  1039.                     err = MyListAllPaperTypes(&myDocument);
  1040.  
  1041.                     if (err)
  1042.                     {
  1043.                         Str255    pStr;
  1044.                         
  1045.                         pStr[0] = sprintf((char *) &pStr[1], "%s --> %i", "Error in MyListAllPaperTypes!", err);
  1046.                         MyDisplayInfo(pStr);
  1047.                     }
  1048.                     break;
  1049.                     
  1050.                 case kShowPrinterResolution:
  1051.                     MyShowJobPrinterResolution(&myDocument);
  1052.                     break;
  1053.                     
  1054.                 }
  1055.             break;
  1056.     }
  1057.  
  1058.     HiliteMenu(0);
  1059. }
  1060.  
  1061.  
  1062. // MyWindowUpdate updates one of our windows.
  1063.  
  1064. void MyWindowUpdate(WindowPtr whichWindow)
  1065. {
  1066.     MyDocumentPtr    myDocument;
  1067.     GrafPtr            oldPort;
  1068.  
  1069.     if (((WindowPeek) whichWindow)->windowKind != userKind) return;
  1070.  
  1071.     GetPort(&oldPort);
  1072.     SetPort(whichWindow);
  1073.     
  1074.     BeginUpdate(whichWindow);
  1075.  
  1076.     myDocument = (MyDocumentPtr) GetWRefCon(whichWindow);
  1077.     EraseRect(&whichWindow->portRect);
  1078.  
  1079.     if (myDocument->numPages > 0)
  1080.         GXDrawShape(myDocument->documentPage[myDocument->curPage -1]);
  1081.  
  1082.     EndUpdate(whichWindow);
  1083.     SetPort(oldPort);
  1084. }
  1085.  
  1086.  
  1087. // This routine handles enabling and disabling menu items
  1088. // when we're putting up, or tearing down print dialogs.
  1089.  
  1090. void MyAdjustMenusForPrintDialogs(Boolean dialogGoingUp)
  1091. {
  1092.     MenuHandle    fileMenu, editMenu, testMenu;
  1093.  
  1094.     editMenu = GetMHandle(mEdit);
  1095.     fileMenu = GetMHandle(mFile);
  1096.     testMenu = GetMHandle(mTest);
  1097.  
  1098.     if (dialogGoingUp)
  1099.     {
  1100.         DisableItem(fileMenu, 0);
  1101.         DisableItem(testMenu, 0);
  1102.         
  1103.         HiliteMenu(0);
  1104.         DrawMenuBar();
  1105.     }
  1106.     else
  1107.     {
  1108.         DisableItem(editMenu, 0);
  1109.         EnableItem(fileMenu,  0);
  1110.         EnableItem(testMenu,  0);
  1111.         DrawMenuBar();
  1112.     }
  1113.  
  1114.     gInPrintDialog = dialogGoingUp;
  1115. }
  1116.  
  1117.  
  1118. // Override for GXPrintingEvent.  It allows us to update our windows
  1119. // when the moveable modal printing dialogs are moved.
  1120.  
  1121. OSErr MyPrintingEventOverride(EventRecord *anEvent, Boolean filterEvent)
  1122. {
  1123.     OSErr    err = noErr;
  1124.  
  1125. /*    Handle events in whatever way is appropriate.  MyDoEvent is our
  1126.     generic event handler.  We don't pass it events that it shouldn't
  1127.     handle while print dialogs are displayed. */
  1128.  
  1129.     if (!filterEvent)
  1130.         switch (anEvent->what)
  1131.         {
  1132.             case mouseDown:
  1133.             case keyDown:
  1134.             case autoKey:
  1135.                 break;
  1136.             
  1137.             default:
  1138.                 err = MyDoEvent(anEvent);
  1139.         }
  1140.  
  1141.     return err;
  1142. }
  1143.  
  1144.  
  1145. // Change a document's format by using the job format dialog.
  1146.  
  1147. OSErr MyFormatDialog(MyDocumentPtr myDocument)
  1148. {
  1149.     OSErr                    err;
  1150.     gxDialogResult            result;
  1151.     gxEditMenuRecord        editMenuRec;
  1152.  
  1153. // Fill in the location of the application’s Edit menu items and enable
  1154. // the appropriate menu items. 
  1155.  
  1156.     editMenuRec.editMenuID    = mEdit;
  1157.     editMenuRec.cutItem        = kCut;
  1158.     editMenuRec.copyItem    = kCopy;
  1159.     editMenuRec.pasteItem    = kPaste;
  1160.     editMenuRec.clearItem    = kClear;
  1161.     editMenuRec.undoItem    = kUndo;
  1162.  
  1163.     MyAdjustMenusForPrintDialogs(true);
  1164.  
  1165. // Display the Document Setup dialog box.
  1166.  
  1167.     result = GXJobDefaultFormatDialog(myDocument->documentJob, &editMenuRec);
  1168.     err = GXGetJobError(myDocument->documentJob);
  1169.  
  1170. // If the user chooses "Format" and no errors occurred, we perform any
  1171. // document formatting that we need to.
  1172.  
  1173.     if ((err == noErr) && (result == gxOKSelected))
  1174.     {
  1175.         /* 
  1176.             Place your application-specific code here if you need
  1177.             to repaginate the document.
  1178.             .
  1179.             .
  1180.             .
  1181.         */
  1182.     }
  1183.     
  1184.     MyAdjustMenusForPrintDialogs(false);
  1185.  
  1186.     return err;
  1187. }
  1188.     
  1189.  
  1190. // Change the current page's format by using the Format dialog.
  1191.  
  1192. OSErr MyPageFormatDialog(MyDocumentPtr myDocument)
  1193. {
  1194.     OSErr                    err = noErr;
  1195.     gxDialogResult            result;
  1196.     gxEditMenuRecord        editMenuRec;
  1197.     gxFormat                pageFormat;
  1198.     Boolean                    newPgFormat = false;
  1199.  
  1200. // Fill in the location of the application’s Edit menu items and enable
  1201. // the appropriate menu items. 
  1202.  
  1203.     editMenuRec.editMenuID    = mEdit;
  1204.     editMenuRec.cutItem        = kCut;
  1205.     editMenuRec.copyItem    = kCopy;
  1206.     editMenuRec.pasteItem    = kPaste;
  1207.     editMenuRec.clearItem    = kClear;
  1208.     editMenuRec.undoItem    = kUndo;
  1209.  
  1210.     MyAdjustMenusForPrintDialogs(true);
  1211.     
  1212. // If we have an existing page format, we'll modify that.  Otherwise, we'll
  1213. // need to create a new format and use that.
  1214.  
  1215.     if (myDocument->pageFormat[myDocument->curPage -1] != nil)
  1216.         pageFormat = myDocument->pageFormat[myDocument->curPage -1];
  1217.     else
  1218.     {
  1219.         pageFormat = GXNewFormat(myDocument->documentJob);
  1220.         newPgFormat = true;
  1221.         err = GXGetJobError(myDocument->documentJob);
  1222.     }
  1223.  
  1224. // If no errors, display the format dialog.
  1225.  
  1226.     if (err == noErr)
  1227.     {
  1228.         result = GXFormatDialog(pageFormat, &editMenuRec, nil);
  1229.  
  1230.         switch (result)
  1231.         {
  1232.  
  1233. // If the user selected "Revert", use the default job format with this page.
  1234. // For our application, we indicate this by storing nil for the format
  1235. // reference in our structure.
  1236. //
  1237. // If "OK" was selected, store the new format with this page.
  1238.  
  1239.             case gxRevertSelected:
  1240.                 GXDisposeFormat(pageFormat);
  1241.                 pageFormat = nil;
  1242.  
  1243.             case gxOKSelected:
  1244.             myDocument->pageFormat[myDocument->curPage -1] = pageFormat;
  1245.  
  1246.             /* 
  1247.                 Place code here if your application needs to 
  1248.                 adjust the document based on the new page format.
  1249.                 .
  1250.                 .
  1251.                 .
  1252.                 
  1253.             */
  1254.                 break;
  1255.  
  1256.  
  1257. // If the user selected "Cancel", dispose of our cloned copy of the default
  1258. // job format, if we made one.
  1259.  
  1260.             case gxCancelSelected:
  1261.                 if (newPgFormat) GXDisposeFormat(pageFormat);
  1262.                 break;
  1263.         }
  1264.     }
  1265.  
  1266.     MyAdjustMenusForPrintDialogs(false);
  1267.  
  1268.     return err;
  1269. }
  1270.  
  1271.  
  1272. // Change the current page's format to the passed format.
  1273.  
  1274. OSErr MyApplyPageFormat(MyDocumentPtr myDocument, gxFormat aNewFormat)
  1275. {
  1276.     OSErr        err = noErr;
  1277.     gxFormat    pageFormat;
  1278.  
  1279. // If the passed format is not the same as the job format (or nil), clone it so
  1280. // it can be shared by different pages.  If it is the job format (or nil), set
  1281. // our reference to nil, which tells our application to use the job format for
  1282. // this page.
  1283.  
  1284.     if ((aNewFormat != nil) && (aNewFormat != GXGetJobFormat(myDocument->documentJob, 1)))
  1285.     {
  1286.         pageFormat = GXCloneFormat(aNewFormat);
  1287.         err = GXGetJobError(myDocument->documentJob);
  1288.     }
  1289.     else
  1290.         pageFormat = nil;
  1291.  
  1292.  
  1293. // If there are no errors, dispose of the old page format and store
  1294. // the new one.  Reformat the page, if need be.
  1295.  
  1296.     if (err == noErr)
  1297.     {
  1298.         if (myDocument->pageFormat[myDocument->curPage -1] != nil)
  1299.             GXDisposeFormat(myDocument->pageFormat[myDocument->curPage -1]);
  1300.  
  1301.         myDocument->pageFormat[myDocument->curPage -1] = pageFormat;
  1302.  
  1303.         /* 
  1304.             Place code here if your application needs to 
  1305.             adjust the document based on the new page format.
  1306.             .
  1307.             .
  1308.             .
  1309.             
  1310.         */
  1311.     }
  1312.     
  1313.     return err;
  1314. }
  1315.  
  1316.  
  1317. // This is our override for FormatDialog.  We add a panel and forward the message
  1318. // so that other handlers are called.
  1319.  
  1320. OSErr MyFormatDialogOverride(gxFormat aFormat, StringPtr title, gxDialogResult *result)
  1321. {
  1322.     OSErr    err;
  1323.     
  1324.     err = MySetUpByPagePanel(aFormat, GXGetMessageHandlerResFile());
  1325.     if (!err) err = Forward_GXFormatDialog(aFormat, title, result);
  1326.  
  1327.     return err;
  1328. }
  1329.  
  1330.  
  1331. // This is the routine which adds our panel to the format dialog.
  1332.  
  1333. OSErr MySetUpByPagePanel(gxFormat aFormat, short ourResFile)
  1334. {
  1335.     OSErr                        err;
  1336.     Collection                    fmtCollection;
  1337.     gxPanelSetupRecord            panelInfo;
  1338.     MyKindaCollectionRec        mySettings;
  1339.  
  1340. // We first get the format collection, and then look for one of our collection
  1341. // items in it.  This collection item is where our default settings will be stored.
  1342.  
  1343.     fmtCollection = GXGetFormatCollection(aFormat);
  1344.  
  1345.     err = GetCollectionItem(fmtCollection, kMyKindaCollectionType,
  1346.                               kMyKindaCollectionTagID, nil, &mySettings);
  1347.  
  1348. // If our collection item does not exist, create one and add it to the format
  1349. // collection so that we have default settings for our dialog panel.
  1350.  
  1351.     if (err == collectionItemNotFoundErr)
  1352.     {
  1353.         mySettings.isTurnedOn    = false;
  1354.         mySettings.dayOfWeek    = 7;
  1355.  
  1356.         err = AddCollectionItem(fmtCollection, kMyKindaCollectionType,
  1357.                                 kMyKindaCollectionTagID, sizeof(MyKindaCollectionRec),
  1358.                                 &mySettings);
  1359.     }
  1360.  
  1361. // Now, install our panel.  We need to specify the type of panel it is, the resource ID
  1362. // of our 'panl' resource, and in which resource file it's located.  The refCon field is
  1363. // for our own use, although we don't use it here.
  1364.  
  1365.     if (!err)
  1366.     {
  1367.         panelInfo.panelKind            = gxApplicationPanel;
  1368.         panelInfo.panelResId        = r_MyFormatPanelResID;
  1369.         panelInfo.resourceRefNum    = ourResFile;
  1370.         panelInfo.refCon            = 0;
  1371.         
  1372.         err = GXSetupDialogPanel(&panelInfo);
  1373.     }
  1374.  
  1375.     return err;
  1376. }
  1377.  
  1378.  
  1379. OSErr MyPrintDocument(MyDocumentPtr myDocument)
  1380. {
  1381. //    return    MyPrintDocument1(myDocument);    // printpage w/o formats
  1382. //    return    MyPrintDocument2(myDocument);    // startpage/finishpage w/o formats
  1383.     return    MyPrintDocument3(myDocument);    // printpage & by-page formats
  1384. //    return    MyPrintDocument4(myDocument);    // printpage & poll after indiv. functions
  1385. }
  1386.  
  1387.  
  1388. // This routine prints the pages of a document using GXPrintPage.  You would
  1389. // use this function if your application stored the data for each page as
  1390. // single shapes.
  1391.  
  1392. OSErr MyPrintDocument1(MyDocumentPtr myDocument)
  1393. {
  1394.     OSErr    err;
  1395.     long    firstPage, lastPage, numPages, pg;
  1396.     
  1397. // Determine which pages the user selected to print.  If the user specifies
  1398. // a page range that is greater than the actual number of pages in the
  1399. // document, only print those pages that are actually in the document. 
  1400.  
  1401.     GXGetJobPageRange(myDocument->documentJob, &firstPage, &lastPage);
  1402.     
  1403.     if (lastPage > myDocument->numPages)
  1404.         lastPage = myDocument->numPages;
  1405.  
  1406. // Calculate the total number of pages to print, and begin printing if there
  1407. // are no errors.
  1408.  
  1409.     numPages = lastPage - firstPage +1;
  1410.     err = GXGetJobError(myDocument->documentJob);
  1411.  
  1412.     if (err == noErr)
  1413.     {
  1414.  
  1415. // Start printing.
  1416.  
  1417.         GXStartJob(myDocument->documentJob, myDocument->documentTitle, numPages);
  1418.         err = GXGetJobError(myDocument->documentJob);
  1419.  
  1420. // Loop through each page of the document, calling GXPrintPage for each page's
  1421. // shape.  In this example, we use the job's default format to print each page.
  1422. // After sending each page, check for errors so that we can exit the loop
  1423. // if any occur.
  1424.  
  1425.         if (err == noErr)
  1426.         {
  1427.             for (pg = firstPage; (err == noErr) && (pg <= lastPage); pg++)
  1428.             {
  1429.                 GXPrintPage(myDocument->documentJob,
  1430.                             pg,
  1431.                             GXGetJobFormat(myDocument->documentJob, 1),
  1432.                             myDocument->documentPage[pg -1]);                                
  1433.     
  1434.                 err = GXGetJobError(myDocument->documentJob);
  1435.             }
  1436.  
  1437. // Finish printing.
  1438.  
  1439.             GXFinishJob(myDocument->documentJob);
  1440.             err = GXGetJobError(myDocument->documentJob);
  1441.         }
  1442.     }
  1443.  
  1444.     return err;
  1445. }
  1446.  
  1447.  
  1448. // This routine prints the pages of a document using GXStartPage, GXDrawShape, and
  1449. // GXFinishPage.  You would normally use this function if your application stored
  1450. // the data for each page as multiple shapes.
  1451.  
  1452. OSErr MyPrintDocument2(MyDocumentPtr myDocument)
  1453. {
  1454.     OSErr    err;
  1455.     long    firstPage, lastPage, numPages, pg;
  1456.     
  1457. // Determine which pages the user selected to print.  If the user specifies
  1458. // a page range that is greater than the actual number of pages in the
  1459. // document, only print those pages that are actually in the document. 
  1460.  
  1461.     GXGetJobPageRange(myDocument->documentJob, &firstPage, &lastPage);
  1462.     
  1463.     if (lastPage > myDocument->numPages)
  1464.         lastPage = myDocument->numPages;
  1465.  
  1466. // Calculate the total number of pages to print, and begin printing if there
  1467. // are no errors.
  1468.  
  1469.     numPages = lastPage - firstPage +1;
  1470.     err = GXGetJobError(myDocument->documentJob);
  1471.  
  1472.     if (err == noErr)
  1473.     {
  1474.  
  1475. // Start printing.
  1476.  
  1477.         GXStartJob(myDocument->documentJob, myDocument->documentTitle, numPages);
  1478.         err = GXGetJobError(myDocument->documentJob);
  1479.  
  1480. // For each page we print, call GXStartPage, draw, and call GXFinishPage.  In this
  1481. // example, we use the job's default format, the document's viewPort, and draw
  1482. // only a single shape for each page.
  1483.  
  1484.         if (err == noErr)
  1485.         {
  1486.             for (pg = firstPage; (err == noErr) && (pg <= lastPage); pg++)
  1487.             {
  1488. // Start the page.
  1489.  
  1490.                 GXStartPage(myDocument->documentJob,
  1491.                           pg,
  1492.                           GXGetJobFormat(myDocument->documentJob, 1),
  1493.                           1,
  1494.                           &myDocument->documentViewPort);                                
  1495.     
  1496.                 err = GXGetJobError(myDocument->documentJob);
  1497.             
  1498. // If there were no errors, draw the data for the page.
  1499.  
  1500.                 if (err == noErr)
  1501.                 {
  1502.                     GXDrawShape(myDocument->documentPage[pg -1]);
  1503.                     err = (OSErr) GXGetGraphicsError(nil);
  1504.                 }
  1505.                     
  1506. // Finish the page, even if there were errors.
  1507.  
  1508.                 GXFinishPage(myDocument->documentJob);
  1509.             }
  1510.  
  1511. // Finish printing.
  1512.  
  1513.             GXFinishJob(myDocument->documentJob);
  1514.             err = GXGetJobError(myDocument->documentJob);
  1515.         }
  1516.     }
  1517.  
  1518.     return err;
  1519. }
  1520.  
  1521.  
  1522. // This routine prints the pages of a document using GXPrintPage.  It also
  1523. // prints using the stored page formats for this document.  You would use
  1524. // this function if your application stored the data for each page as
  1525. // single shapes.
  1526.  
  1527. OSErr MyPrintDocument3(MyDocumentPtr myDocument)
  1528. {
  1529.     OSErr        err;
  1530.     long        firstPage, lastPage, numPages, pg;
  1531.     gxFormat    pgFormat;
  1532.     
  1533. // Determine which pages the user selected to print.  If the user specifies
  1534. // a page range that is greater than the actual number of pages in the
  1535. // document, only print those pages that are actually in the document. 
  1536.  
  1537.     GXGetJobPageRange(myDocument->documentJob, &firstPage, &lastPage);
  1538.     
  1539.     if (lastPage > myDocument->numPages)
  1540.         lastPage = myDocument->numPages;
  1541.  
  1542. // Calculate the total number of pages to print, and begin printing if there
  1543. // are no errors.
  1544.  
  1545.     numPages = lastPage - firstPage +1;
  1546.     err = GXGetJobError(myDocument->documentJob);
  1547.  
  1548.     if (err == noErr)
  1549.     {
  1550.  
  1551. // Start printing.
  1552.  
  1553.         GXStartJob(myDocument->documentJob, myDocument->documentTitle, numPages);
  1554.         err = GXGetJobError(myDocument->documentJob);
  1555.         
  1556.         
  1557. // Loop through each page of the document, calling GXPrintPage for each page's
  1558. // shape.  In this example, we use the job's default format to print each
  1559. // page.  After sending each page, check for errors so that we can exit the
  1560. // loop if any occur.
  1561.  
  1562.         if (err == noErr)
  1563.         {
  1564.             for (pg = firstPage; (err == noErr) && (pg <= lastPage); pg++)
  1565.             {
  1566.                 pgFormat = myDocument->pageFormat[pg -1];
  1567.                 
  1568.                 if (pgFormat == nil)
  1569.                     pgFormat = GXGetJobFormat(myDocument->documentJob, 1);
  1570.                 
  1571.                 GXPrintPage(myDocument->documentJob,
  1572.                             pg,
  1573.                             pgFormat,
  1574.                             myDocument->documentPage[pg -1]);                                
  1575.     
  1576.                 err = GXGetJobError(myDocument->documentJob);
  1577.             }
  1578.  
  1579. // Finish printing.
  1580.  
  1581.             GXFinishJob(myDocument->documentJob);
  1582.             err = GXGetJobError(myDocument->documentJob);
  1583.         }
  1584.     }
  1585.  
  1586.     return err;
  1587. }
  1588.  
  1589.  
  1590. // This routine prints the pages of a document using GXPrintPage.  You would
  1591. // use this function if your application stored the data for each page as
  1592. // single shapes.
  1593.  
  1594. OSErr MyPrintDocument4(MyDocumentPtr myDocument)
  1595. {
  1596.     OSErr    err;
  1597.     long    firstPage, lastPage, numPages, pg;
  1598.     
  1599. // Determine which pages the user selected to print.  If the user specifies
  1600. // a page range that is greater than the actual number of pages in the
  1601. // document, only print those pages that are actually in the document. 
  1602.  
  1603.     GXGetJobPageRange(myDocument->documentJob, &firstPage, &lastPage);
  1604.     err = GXGetJobError(myDocument->documentJob);
  1605.  
  1606.     if (err == noErr)
  1607.     {
  1608.         if (lastPage > myDocument->numPages)
  1609.             lastPage = myDocument->numPages;
  1610.  
  1611. // Calculate the total number of pages to print, and begin printing if there
  1612. // are no errors.
  1613.  
  1614.         numPages = lastPage - firstPage + 1;
  1615.     
  1616.         GXStartJob(myDocument->documentJob, myDocument->documentTitle, numPages);
  1617.         err = GXGetJobError(myDocument->documentJob);
  1618.  
  1619. // Loop through each page of the document, calling GXPrintPage for each page's
  1620. // shape.
  1621.     
  1622.         if (err == noErr)
  1623.         {
  1624.             for (pg = firstPage; (err == noErr) && (pg <= lastPage); pg++)
  1625.             {
  1626.                 GXPrintPage(myDocument->documentJob,
  1627.                           pg,
  1628.                           GXGetJobFormat(myDocument->documentJob, 1),
  1629.                           myDocument->documentPage[pg -1]);                                
  1630.         
  1631.                 err = GXGetJobError(myDocument->documentJob);
  1632.             }
  1633.     
  1634. // Finish printing.
  1635.     
  1636.             GXFinishJob(myDocument->documentJob);
  1637.             err = GXGetJobError(myDocument->documentJob);
  1638.         }
  1639.     }
  1640.  
  1641.     return err;
  1642. }
  1643.  
  1644.  
  1645. // This routine sets up our job's collection items
  1646. // to correctly print one full copy of the document,
  1647. // and then it initiates printing.
  1648.  
  1649. OSErr MyPrintOneCopy(MyDocumentPtr whichDocument)
  1650. {
  1651.     OSErr                    err;
  1652.     Collection                jobCollection;
  1653.     gxCopiesInfo            copiesInfo;
  1654.     gxFileDestinationInfo    destInfo;
  1655.     gxPageRangeInfo            pageRangeInfo;
  1656.     Ptr                        oldCopiesInfo = nil, oldPageRangeInfo = nil, oldDestInfo = nil;
  1657.     long                    oldCopiesSize, oldPageRangeInfoSize, oldDestInfoSize;
  1658.  
  1659.  
  1660. /* Get the job collection and set it up to print one copy…    */
  1661.  
  1662.     jobCollection = GXGetJobCollection(whichDocument->documentJob);
  1663.  
  1664.  
  1665. /* Set number of copies to 1.            */
  1666.     
  1667.     copiesInfo.copies = 1;
  1668.     err = MyReplaceCollectionItem(&copiesInfo, sizeof(gxCopiesInfo),
  1669.                                     gxCopiesTag, gxPrintingTagID,
  1670.                                     jobCollection, &oldCopiesInfo, &oldCopiesSize);
  1671.     nrequire(err, ReplaceCopies_error);
  1672.  
  1673.  
  1674. /* Set page range to "all".    */
  1675.     
  1676.     pageRangeInfo.simpleRange.optionChosen = gxDefaultPageRange;
  1677.     pageRangeInfo.minFromPage = 1;
  1678.     pageRangeInfo.simpleRange.fromPage = 1;
  1679.     pageRangeInfo.maxToPage = whichDocument->numPages;
  1680.     pageRangeInfo.simpleRange.toPage = whichDocument->numPages;
  1681.     pageRangeInfo.simpleRange.printAll = true;
  1682.     err = MyReplaceCollectionItem(&pageRangeInfo, sizeof(gxPageRangeInfo),
  1683.                                     gxPageRangeTag, gxPrintingTagID,
  1684.                                     jobCollection, &oldPageRangeInfo, &oldPageRangeInfoSize);
  1685.     nrequire(err, ReplacePageRange_error);
  1686.  
  1687.  
  1688. /* Set destination to "printer".        */
  1689.  
  1690.     destInfo.toFile = false;
  1691.     err = MyReplaceCollectionItem(&destInfo, sizeof(gxFileDestinationInfo),
  1692.                                   gxFileDestinationTag, gxPrintingTagID,
  1693.                                   jobCollection, &oldDestInfo, &oldDestInfoSize);
  1694.     nrequire(err, ReplaceDestination_error);
  1695.  
  1696.  
  1697. /* Print one copy of our document.        */
  1698.  
  1699.     err = MyPrintDocument(whichDocument);
  1700.  
  1701.  
  1702. /*    Restore original number of copies, page range, and output
  1703.     destination in case anybody uses that info. */
  1704.  
  1705. ReplaceCopies_error:
  1706.     MyReplaceCollectionItem(oldCopiesInfo, oldCopiesSize,
  1707.                               gxCopiesTag, gxPrintingTagID,
  1708.                             jobCollection, nil, nil);
  1709.  
  1710. ReplacePageRange_error:
  1711.     MyReplaceCollectionItem(oldPageRangeInfo, oldPageRangeInfoSize,
  1712.                             gxPageRangeTag, gxPrintingTagID,
  1713.                             jobCollection, nil, nil);
  1714.  
  1715. ReplaceDestination_error:
  1716.     MyReplaceCollectionItem(oldDestInfo, oldDestInfoSize,
  1717.                             gxFileDestinationTag, gxPrintingTagID,
  1718.                             jobCollection, nil, nil);
  1719.  
  1720.  
  1721. /* Dispose of the pointers that MyReplaceCollectionItem created. */
  1722.  
  1723.     if (oldCopiesInfo)
  1724.         DisposePtr(oldCopiesInfo);
  1725.  
  1726.     if (oldPageRangeInfo)
  1727.         DisposePtr(oldPageRangeInfo);
  1728.  
  1729.     if (oldDestInfo)
  1730.         DisposePtr(oldDestInfo);
  1731.  
  1732.     return err;
  1733. }
  1734.  
  1735.  
  1736. //    MyReplaceCollectionItem is a generic routine that replaces a
  1737. //    collection item with the passed data.  If the oldData pointer
  1738. //    is not nil, the data that's being replaced is returned in it.
  1739. //    (If the item doesn't already exist, then a copy of the newData
  1740. //    is returned instead.)
  1741.  
  1742. OSErr MyReplaceCollectionItem(void *newData, long collectSize,
  1743.                               OSType collectType, long collectID,
  1744.                               Collection whichCollection,
  1745.                               Ptr *oldData, long *oldDataSize)
  1746. {
  1747.     OSErr    err = noErr;
  1748.     long    index;
  1749.  
  1750. /*
  1751.     If we're supposed to return the old data, get it.
  1752.     If there is no old data, return a copy of the new data.
  1753. */
  1754.  
  1755.     if (oldData)
  1756.     {
  1757.         err = GetCollectionItemInfo(whichCollection,
  1758.                                     collectType,
  1759.                                     collectID,
  1760.                                     dontWantIndex,
  1761.                                     oldDataSize,
  1762.                                     dontWantAttributes);
  1763.  
  1764.         if (err)
  1765.         {
  1766.             *oldDataSize = collectSize;
  1767.             *oldData = NewPtrSys(*oldDataSize);
  1768.             if (!(err = MemError()))
  1769.                 BlockMove(newData, *oldData, collectSize);
  1770.         }
  1771.         else
  1772.         {
  1773.             *oldData = NewPtrSys(*oldDataSize);
  1774.             if (!(err = MemError()))
  1775.                 err = GetCollectionItem(whichCollection,
  1776.                                         collectType,
  1777.                                         collectID,
  1778.                                         dontWantSize,
  1779.                                         *oldData);
  1780.         }
  1781.     }
  1782.  
  1783.     nrequire(err, CouldNotSetOldData);
  1784.  
  1785.  
  1786. // If we're adding a new collection item, do so.  Otherwise, get the
  1787. // existing item's index and replace the old collection item.
  1788.  
  1789.     err = AddCollectionItem(whichCollection,
  1790.                             collectType,
  1791.                             collectID,
  1792.                             collectSize,
  1793.                             newData);
  1794.  
  1795.     if (err == collectionItemLockedErr)
  1796.     {
  1797.         err = GetCollectionItemInfo(whichCollection,
  1798.                                     collectType,
  1799.                                     collectID,
  1800.                                     &index,
  1801.                                     dontWantSize,
  1802.                                     dontWantAttributes);
  1803.         if (!err)
  1804.             err = ReplaceIndexedCollectionItem(whichCollection,
  1805.                                                index,
  1806.                                                collectSize,
  1807.                                                newData);
  1808.     }
  1809.  
  1810. CouldNotSetOldData:
  1811.     return err;
  1812. }
  1813.  
  1814.  
  1815. gxColorProfile MyGetFormattingPrinterProfile(MyDocumentPtr myDocument, gxColorSpace *theSpace)
  1816. {
  1817.     gxShape            deviceBitMap;
  1818.     gxBitmap        deviceBits;
  1819.     gxPrinter        formattingPrinter;
  1820.     gxColorProfile    theProfile;
  1821.     gxViewDevice    printerDevice;
  1822.  
  1823. /*    Get the first profile for the formatting printer. */
  1824.  
  1825.     formattingPrinter = GXGetJobFormattingPrinter(myDocument->documentJob);
  1826.     GXFindPrinterProfile(formattingPrinter, nil, 1, &theProfile);
  1827.  
  1828. /*
  1829.     Now look at the characteristics of the formatting printer's
  1830.     viewdevice and retrieve its color space.
  1831. */
  1832.     printerDevice = GXGetPrinterViewDevice(formattingPrinter, 0);
  1833.     deviceBitMap = GXGetViewDeviceBitmap(printerDevice);
  1834.     GXGetBitmap(deviceBitMap, &deviceBits, nil);
  1835.     *theSpace = deviceBits.space;
  1836.     GXDisposeShape(deviceBitMap);
  1837.  
  1838.     return theProfile;
  1839. }
  1840.  
  1841.  
  1842. Boolean MyMakePrinterColor(MyDocumentPtr myDocument, gxColor *sourceColor, gxColor *printedColor)
  1843. {
  1844.     gxColorProfile    printerProfile;
  1845.     gxColorSpace    printerSpace;
  1846.     Boolean            inGamut;
  1847.  
  1848.     printerProfile = MyGetFormattingPrinterProfile(myDocument, &printerSpace);
  1849.  
  1850. /*
  1851.     Copy the source color, see if it's in gamut, and convert it
  1852.     into the device's color space.
  1853. */
  1854.  
  1855.     *printedColor = *sourceColor;
  1856.     inGamut = GXCheckColor(printedColor, printerSpace, nil, printerProfile);
  1857.     GXConvertColor(printedColor, printerSpace, nil, printerProfile);
  1858.  
  1859.     return inGamut;
  1860. }
  1861.  
  1862.  
  1863. OSErr MyPrintDialog(MyDocumentPtr myDocument)
  1864. {
  1865.     OSErr                err = noErr;
  1866.     gxDialogResult        result;
  1867.     gxEditMenuRecord    editMenuRec;
  1868.  
  1869. /*
  1870.     Fill in the location of the application’s Edit menu
  1871.     items and enable the appropriate menu items.
  1872. */
  1873.     editMenuRec.editMenuID    = mEdit;
  1874.     editMenuRec.cutItem        = kCut;
  1875.     editMenuRec.copyItem    = kCopy;
  1876.     editMenuRec.pasteItem    = kPaste;
  1877.     editMenuRec.clearItem    = kClear;
  1878.     editMenuRec.undoItem    = kUndo;
  1879.  
  1880.     MyAdjustMenusForPrintDialogs(true);
  1881.  
  1882. /*
  1883.     Uncommenting any one of these lines will alter the appearance
  1884.     of the page range fields in the General Print panel.  However,
  1885.     this only works correctly for f2c1.2 or later!!!!
  1886.     
  1887.     You must also uncomment both GXInstallApplicationOverride calls
  1888.     below.
  1889. */
  1890.  
  1891. //    err = MyConfigurePageRange1(myDocument);
  1892. //    err = MyConfigurePageRange2(myDocument);
  1893. //    err = MyConfigurePageRange3(myDocument);
  1894.     nrequire(err, CouldNotConfigurePageRange);
  1895.  
  1896. //    GXInstallApplicationOverride(myDocument->documentJob, gxParsePageRange, NewGXParsePageRangeProc(MyParsePageRangeOverride));
  1897.  
  1898. /*    Display the Print dialog box. */
  1899.  
  1900.     result = GXJobPrintDialog(myDocument->documentJob, &editMenuRec);
  1901.     err = GXGetJobError(myDocument->documentJob);
  1902.  
  1903. //    GXInstallApplicationOverride(myDocument->documentJob, gxParsePageRange, NewGXParsePageRangeProc(nil));
  1904.  
  1905.  
  1906. /*
  1907.     If we didn't receive any errors and the user selected the
  1908.     “OK” button, call our printing routine to output the pages.
  1909. */
  1910.     if ((err == noErr) && (result == gxOKSelected))
  1911.         err = MyPrintDocument(myDocument);
  1912.  
  1913. CouldNotConfigurePageRange:
  1914.     MyAdjustMenusForPrintDialogs(false);
  1915.  
  1916.     return err;
  1917. }
  1918.  
  1919.  
  1920. /*
  1921.     In this routine, we're supposed to check the validity of the "From page"
  1922.     and "To page" strings.  If both are good, return gxRangeParsed.
  1923.     Otherwise, return gxRangeBadFromValue or gxRangeBadToValue.  Being a
  1924.     cheesy sample, we always return gxRangeParsed.
  1925. */
  1926.  
  1927. gxParsePageRangeResult MyPageRangeValidityCheck(StringPtr fromString, StringPtr toString)
  1928. {
  1929.     #pragma unused(fromString, toString)
  1930.  
  1931.     return gxRangeParsed;
  1932. }
  1933.  
  1934.  
  1935. //    This is an override for gxParsePageRange.  In here,
  1936. //    we verify that the user's page range is valid.
  1937.  
  1938. OSErr MyParsePageRangeOverride(StringPtr fromString, StringPtr toString, gxParsePageRangeResult *result)
  1939. {
  1940.  
  1941. /*
  1942.     Determine if the "To page" and "From page" strings are
  1943.     valid.  If not, our MyPageRangeValidityCheck routine
  1944.     will return gxRangeBadFromValue or gxRangeBadToValue.
  1945.     Otherwise it will return gxRangeParsed.
  1946. */
  1947.     if (*result == gxRangeNotParsed)
  1948.         *result = MyPageRangeValidityCheck(fromString, toString);
  1949.  
  1950.     return noErr;
  1951. }
  1952.  
  1953.  
  1954. // This routine sets up the page range collection item to
  1955. // use the default page range style (numeric).
  1956.  
  1957. OSErr MyConfigurePageRange1(MyDocumentPtr myDocument)
  1958. {
  1959.     OSErr                err;
  1960.     gxPageRangeInfo        **pageRangeHdl;
  1961.  
  1962. /*
  1963.     Create a handle to store the page range collection itme in,
  1964.     and then retrieve it.
  1965. */
  1966.     pageRangeHdl = (gxPageRangeInfo **) NewHandleClear(sizeof(gxPageRangeInfo));
  1967.     nrequire_action(err, NewHandleClear_Failed, err = MemError(););
  1968.  
  1969.     err = GetCollectionItemHdl(GXGetJobCollection(myDocument->documentJob),
  1970.                                gxPageRangeTag,
  1971.                                gxPrintingTagID,
  1972.                                (Handle) pageRangeHdl);
  1973.  
  1974.     nrequire(err, GetCollectionItemHdl_Failed);
  1975.  
  1976. /*
  1977.     Indicate that we're using the default page range format, and that
  1978.     we don't want the "all pages" radio button selected.  We also
  1979.     indicate that we're printing pages 1 through 4.
  1980. */
  1981.     (*pageRangeHdl)->simpleRange.optionChosen = gxDefaultPageRange;
  1982.     (*pageRangeHdl)->simpleRange.printAll = false;
  1983.  
  1984.     (*pageRangeHdl)->simpleRange.fromPage = 1;
  1985.     (*pageRangeHdl)->simpleRange.toPage = 4;
  1986.     (*pageRangeHdl)->minFromPage = 1;
  1987.     (*pageRangeHdl)->maxToPage = 9999;
  1988.  
  1989. /*    Add (or replace) the collection item, and dispose of its handle.    */
  1990.  
  1991.     err = AddCollectionItemHdl(GXGetJobCollection(myDocument->documentJob),
  1992.                                gxPageRangeTag,
  1993.                                gxPrintingTagID,
  1994.                                (Handle) pageRangeHdl);
  1995.  
  1996. GetCollectionItemHdl_Failed:
  1997.     DisposHandle((Handle) pageRangeHdl);
  1998.  
  1999. NewHandleClear_Failed:
  2000.     return err;
  2001. }
  2002.  
  2003.  
  2004. // This routine sets up the page range collection item to
  2005. // use the replace page range style, which replaces the
  2006. // "From-To" editText fields with one editText field.
  2007.  
  2008. OSErr MyConfigurePageRange2(MyDocumentPtr myDocument)
  2009. {
  2010.     OSErr                    err;
  2011.     gxPageRangeInfo            **pageRangeHdl;
  2012.     Str31                    FromToTitle = "\pChapter 5";
  2013.     long                    titleSize = FromToTitle[0] +1;
  2014.  
  2015. /*
  2016.     Create a handle to store the page range collection itme in,
  2017.     and then retrieve it.
  2018. */
  2019.     pageRangeHdl = (gxPageRangeInfo **) NewHandleClear(sizeof(gxPageRangeInfo));
  2020.     nrequire_action(err, NewHandleClear_Failed, err = MemError(););
  2021.  
  2022.     err = GetCollectionItemHdl(GXGetJobCollection(myDocument->documentJob),
  2023.                                gxPageRangeTag,
  2024.                                gxPrintingTagID,
  2025.                                (Handle) pageRangeHdl);
  2026.  
  2027.     nrequire(err, GetCollectionItemHdl_Failed);
  2028.  
  2029. /*
  2030.     Indicate that we're replacing the "From-To" dialog items with
  2031.     one editText field, and that we don't want the "all pages"
  2032.     radio button selected.  We also indicate that we want the
  2033.     second radio button's editText field to be set to our title,
  2034.     "Chapter 5".
  2035. */
  2036.     (*pageRangeHdl)->simpleRange.optionChosen = gxReplacePageRange;
  2037.     (*pageRangeHdl)->simpleRange.printAll = false;
  2038.  
  2039.     SetHandleSize((Handle) pageRangeHdl, sizeof(gxPageRangeInfo) +titleSize -1);
  2040.     nrequire_action(err, SetHandleSize_Failed, err = MemError(););
  2041.  
  2042.     BlockMove(FromToTitle, (*pageRangeHdl)->replaceString, titleSize);
  2043.  
  2044. /*    Add (or replace) the collection item, and dispose of its handle.    */
  2045.  
  2046.     err = AddCollectionItemHdl(GXGetJobCollection(myDocument->documentJob),
  2047.                                gxPageRangeTag,
  2048.                                gxPrintingTagID,
  2049.                                (Handle) pageRangeHdl);
  2050.  
  2051. SetHandleSize_Failed:
  2052. GetCollectionItemHdl_Failed:
  2053.     DisposHandle((Handle) pageRangeHdl);
  2054.  
  2055. NewHandleClear_Failed:
  2056.     return err;
  2057. }
  2058.  
  2059.  
  2060. // This routine sets up the page range collection item to
  2061. // use the custom page range style, which uses the
  2062. // "From-To" editText fields but allows non-standard
  2063. // page numbering.
  2064.  
  2065. OSErr MyConfigurePageRange3(MyDocumentPtr myDocument)
  2066. {
  2067.     OSErr                    err;
  2068.     gxPageRangeInfo            **pageRangeHdl;
  2069.  
  2070. /*
  2071.     Create a handle to store the page range collection itme in,
  2072.     and then retrieve it.
  2073. */
  2074.     pageRangeHdl = (gxPageRangeInfo **) NewHandleClear(sizeof(gxPageRangeInfo));
  2075.     nrequire_action(err, NewHandleClear_Failed, err = MemError(););
  2076.  
  2077.     err = GetCollectionItemHdl(GXGetJobCollection(myDocument->documentJob),
  2078.                                gxPageRangeTag,
  2079.                                gxPrintingTagID,
  2080.                                (Handle) pageRangeHdl);
  2081.  
  2082.     nrequire(err, GetCollectionItemHdl_Failed);
  2083.  
  2084. /*
  2085.     Indicate that we're using the standard "From-To" editText fields,
  2086.     but are using a custom format for our page range values.  Specify
  2087.     that we don't want the "all pages" radio button selected and that
  2088.     we want the "From" field to contain "iii" and the "To" field to
  2089.     contain "VI".
  2090. */
  2091.     (*pageRangeHdl)->simpleRange.optionChosen = gxCustomizePageRange;
  2092.     (*pageRangeHdl)->simpleRange.printAll = false;
  2093.  
  2094.     BlockMove("iii", &(*pageRangeHdl)->fromString[1], 3);
  2095.     (*pageRangeHdl)->fromString[0] = 3;
  2096.     BlockMove("VI", &(*pageRangeHdl)->toString[1], 2);
  2097.     (*pageRangeHdl)->toString[0] = 2;
  2098.  
  2099. /*    Add (or replace) the collection item, and dispose of its handle.    */
  2100.  
  2101.     err = AddCollectionItemHdl(GXGetJobCollection(myDocument->documentJob),
  2102.                                gxPageRangeTag,
  2103.                                gxPrintingTagID,
  2104.                                (Handle) pageRangeHdl);
  2105.  
  2106. GetCollectionItemHdl_Failed:
  2107.     DisposHandle((Handle) pageRangeHdl);
  2108.  
  2109. NewHandleClear_Failed:
  2110.     return err;
  2111. }
  2112.  
  2113.  
  2114. // Create a new document.  docName is a Pascal string containing the
  2115. // name of the document, myDocument is a pointer to one of our
  2116. // MyDocumentRec structures.
  2117.  
  2118. OSErr MyNewDocument(Str31 docName, MyDocumentPtr myDocument)
  2119. {    
  2120.     OSErr        err;
  2121.     Rect        bounds;
  2122.  
  2123.     myDocument->numPages = 0;                    // There are no pages yet.
  2124.     myDocument->curPage = 0;
  2125.     myDocument->documentFSSpec.name[0] = 0;        // Indicates a new document, not one
  2126.                                                 // which has been loaded.
  2127.  
  2128. // Create a new job for our document and install our overrides for
  2129. // PrintingEvent and FormatDialog.
  2130.  
  2131.     err = GXNewJob(&myDocument->documentJob);
  2132.  
  2133.     if (err == noErr)
  2134.     {
  2135.  
  2136. // Now install our application override for PrintingEvent so that we can
  2137. // support the new movable-modal printing dialog boxes.
  2138.  
  2139.         GXInstallApplicationOverride(myDocument->documentJob, gxPrintingEventMsg,
  2140.                                      NewGXPrintingEventProc(MyPrintingEventOverride));
  2141.         GXInstallApplicationOverride(myDocument->documentJob, gxFormatDialogMsg,
  2142.                                      NewGXFormatDialogProc(MyFormatDialogOverride));
  2143.  
  2144.  
  2145. // Store the document name.  We limit our document names to 31 characters
  2146. // (plus a length byte).
  2147.  
  2148.         if (docName[0] > 31)
  2149.             docName[0] = 31;
  2150.         
  2151.         BlockMove(&docName[0], &myDocument->documentTitle[0], (long) docName[0] +1);
  2152.  
  2153.     /*
  2154.         Additional application-specific document initialization can go here.
  2155.  
  2156.         .
  2157.         .
  2158.         .
  2159.  
  2160.         Below, we create a window and a viewport for the document.  We store
  2161.         the pointer to our MyDocumentRec structure in the window's refCon field.
  2162.  
  2163.     */
  2164.  
  2165.         SetRect(&bounds, 30, 60, 400, 500);
  2166.         myDocument->documentWindow = NewWindow(nil, &bounds, docName, false, noGrowDocProc,
  2167.                                                (WindowPtr) -1, true, (long) myDocument);
  2168.         err = MemError();
  2169.         
  2170.         if (err == noErr)
  2171.         {
  2172.             SetPort(myDocument->documentWindow);
  2173.             myDocument->documentViewPort = GXNewWindowViewPort(myDocument->documentWindow);
  2174.             err = GXGetGraphicsError(nil);
  2175.             
  2176.             if (err != noErr) DisposeWindow(myDocument->documentWindow);
  2177.         }
  2178.  
  2179.         if (err != noErr) GXDisposeJob(myDocument->documentJob);
  2180.     }
  2181.  
  2182.     return err;
  2183. }
  2184.  
  2185.  
  2186. // Close the document passed and free up any memory we allocated for it.
  2187.  
  2188. OSErr MyCloseDocument(MyDocumentPtr myDocument)
  2189. {    
  2190.     OSErr    err = noErr, jobErr;
  2191.     long    pg;
  2192.  
  2193. // For each page in the document, dispose of the page's shape.
  2194.  
  2195.     for (pg = 1; pg <= myDocument->numPages; pg++)
  2196.         GXDisposeShape(myDocument->documentPage[pg -1]);
  2197.  
  2198.  
  2199. // Dispose of the the document's job (and job formats).
  2200.  
  2201.     jobErr = GXDisposeJob(myDocument->documentJob);
  2202.     if (err == noErr) err = jobErr;
  2203.  
  2204.     /*
  2205.         Place any application-specific code to close a document here.
  2206.  
  2207.         .
  2208.         .
  2209.         .
  2210.  
  2211.         Below, we dispose of the document's viewPort and window.
  2212.  
  2213.     */
  2214.  
  2215.     GXDisposeViewPort(myDocument->documentViewPort);
  2216.     DisposeWindow(myDocument->documentWindow);
  2217.  
  2218.     return err;
  2219. }
  2220.  
  2221.  
  2222. // This routine saves a document and its corresponding job to disk.  It
  2223. // also saves a format collection item containing our page<->format
  2224. // relationships.
  2225.  
  2226. OSErr MySaveDocument(MyDocumentPtr myDocument, Boolean doingSaveAs)
  2227. {
  2228.     OSErr                err;
  2229.     Handle                theJobData, oldJobData;
  2230.     short                dataRefNum = -1;
  2231.     short                oldResFile, resRefNum = -1;
  2232.     FSSpec                *docFSSpec;
  2233.     StandardFileReply    sfReply;
  2234.     FInfo                docFInfo;
  2235.     
  2236. // Create a handle to store the job in, then flatten the job into our handle.
  2237.  
  2238.     oldResFile = CurResFile();
  2239.     theJobData = NewHandle(0);
  2240.     err = MemError();
  2241.     
  2242.     if (err == noErr)
  2243.     {
  2244.  
  2245. // Store the document's page-to-format correspondences, then flatten the job.
  2246.  
  2247.         err = MySaveFormatRefs(myDocument);
  2248.         
  2249.         if (err == noErr)
  2250.         {
  2251.             GXFlattenJobToHdl(myDocument->documentJob, theJobData);
  2252.             err = GXGetJobError(myDocument->documentJob);
  2253.         }
  2254.  
  2255.         if (err == noErr)
  2256.         {
  2257.             docFSSpec = &myDocument->documentFSSpec;
  2258.  
  2259. // If we're doing a "Save as…", display the StandardFile dialog and have the user
  2260. // select a place to save the file.
  2261.  
  2262.             if (doingSaveAs)
  2263.             {
  2264.                 StandardPutFile("\pSave document:", myDocument->documentTitle, &sfReply);
  2265.  
  2266.                 if (!sfReply.sfGood)
  2267.                     return noErr;
  2268.  
  2269. // If we're replacing an existing file, delete it.  Create our new file and set its
  2270. // creator and type.
  2271.  
  2272.                 if (sfReply.sfReplacing)
  2273.                     err = HDelete(sfReply.sfFile.vRefNum, sfReply.sfFile.parID, sfReply.sfFile.name);
  2274.  
  2275.                 if (err == noErr)
  2276.                 {
  2277.                     HCreateResFile(sfReply.sfFile.vRefNum, sfReply.sfFile.parID, sfReply.sfFile.name);
  2278.                     HGetFInfo(sfReply.sfFile.vRefNum, sfReply.sfFile.parID,
  2279.                               sfReply.sfFile.name, &docFInfo);
  2280.                           
  2281.                     docFInfo.fdCreator = kMyDocCreator;
  2282.                     docFInfo.fdType = kMyDocType;
  2283.  
  2284.                     err = HSetFInfo(sfReply.sfFile.vRefNum, sfReply.sfFile.parID,
  2285.                                     sfReply.sfFile.name, &docFInfo);
  2286.                 }
  2287.  
  2288. // If we're successful in creating the file, set our document's FSSpec info, its
  2289. // title and its window's title.
  2290.  
  2291.                 if (err == noErr)
  2292.                     err = ResError();
  2293.  
  2294.                 if (err) return err;
  2295.     
  2296.                 BlockMove(&sfReply.sfFile, docFSSpec, sizeof(FSSpec));
  2297.                 BlockMove(&sfReply.sfFile.name, myDocument->documentTitle,
  2298.                           (long) sfReply.sfFile.name[0] +1);
  2299.                 
  2300.                 SetWTitle(myDocument->documentWindow, myDocument->documentTitle);
  2301.             }
  2302.  
  2303. // Open the file's data fork and resource fork.
  2304.  
  2305.             err = FSpOpenDF(docFSSpec, fsRdWrPerm, &dataRefNum);
  2306.  
  2307.             if (err == noErr)
  2308.             {
  2309.                 resRefNum = HOpenResFile(docFSSpec->vRefNum, docFSSpec->parID,
  2310.                                          docFSSpec->name, fsRdWrPerm);
  2311.                 err = ResError();
  2312.             }
  2313.  
  2314. // If there's an existing job resource, delete it.
  2315.  
  2316.             if (err == noErr)
  2317.             {
  2318.                 UseResFile(resRefNum);
  2319.                 oldJobData = Get1Resource(kMyJobType, kMyJobID);
  2320.                 if (oldJobData != nil)
  2321.                 {
  2322.                     RmveResource(oldJobData);
  2323.                     UpdateResFile(resRefNum);
  2324.                     DisposHandle(oldJobData);
  2325.                 }
  2326.  
  2327. // Add our new job resource.
  2328.  
  2329.                 AddResource(theJobData, kMyJobType, kMyJobID, "\p");
  2330.                 err = ResError();
  2331.     
  2332.                 if (err == noErr)
  2333.                 {
  2334.                     WriteResource(theJobData);
  2335.                     UpdateResFile(resRefNum);
  2336.                     ReleaseResource(theJobData);
  2337.                 }
  2338.                 
  2339.  
  2340. // Now write out the data for our document's pages.
  2341.                 
  2342.                 /* 
  2343.                     Place your application-specific code here to save 
  2344.                     other data associated with the document.
  2345.                     .
  2346.                     .
  2347.                     .
  2348.                 */
  2349.             }
  2350.  
  2351. // Close the data and resource forks of this document.
  2352.  
  2353.             if (dataRefNum != -1) FSClose(dataRefNum);
  2354.             if (resRefNum  != -1) CloseResFile(resRefNum);
  2355.         }
  2356.         else
  2357.             DisposHandle(theJobData);
  2358.     }
  2359.         
  2360.     UseResFile(oldResFile);
  2361.     return err;
  2362. }
  2363.  
  2364.  
  2365. // This routine saves a document and its corresponding job to disk.
  2366. // It saves the job in the data fork of the document.
  2367.  
  2368. OSErr MySaveDocument2(MyDocumentPtr myDocument, Boolean doingSaveAs)
  2369. {
  2370.     OSErr                err;
  2371.     short                dataRefNum = -1;
  2372.     short                oldResFile, resRefNum = -1;
  2373.     FSSpec                *docFSSpec;
  2374.     StandardFileReply    sfReply;
  2375.     FInfo                docFInfo;
  2376.     
  2377. // Create a handle to store the job in, then flatten the job into our handle.
  2378.  
  2379.     oldResFile = CurResFile();
  2380.     err = MemError();
  2381.     
  2382.     if (err == noErr)
  2383.     {
  2384.         docFSSpec = &myDocument->documentFSSpec;
  2385.  
  2386. // If we're doing a "Save as…", display the StandardFile dialog and have the user
  2387. // select a place to save the file.
  2388.  
  2389.         if (doingSaveAs)
  2390.         {
  2391.             StandardPutFile("\pSave document:", myDocument->documentTitle, &sfReply);
  2392.  
  2393.             if (!sfReply.sfGood)
  2394.                 return noErr;
  2395.  
  2396. // If we're replacing an existing file, delete it.  Create our new file and set its
  2397. // creator and type.
  2398.  
  2399.             if (sfReply.sfReplacing)
  2400.                 err = HDelete(sfReply.sfFile.vRefNum, sfReply.sfFile.parID, sfReply.sfFile.name);
  2401.  
  2402.             if (err == noErr)
  2403.             {
  2404.                 HCreateResFile(sfReply.sfFile.vRefNum, sfReply.sfFile.parID, sfReply.sfFile.name);
  2405.                 HGetFInfo(sfReply.sfFile.vRefNum, sfReply.sfFile.parID,
  2406.                           sfReply.sfFile.name, &docFInfo);
  2407.                       
  2408.                 docFInfo.fdCreator = kMyDocCreator;
  2409.                 docFInfo.fdType = kMyDocType;
  2410.  
  2411.                 err = HSetFInfo(sfReply.sfFile.vRefNum, sfReply.sfFile.parID,
  2412.                                 sfReply.sfFile.name, &docFInfo);
  2413.             }
  2414.  
  2415. // If we're successful in creating the file, set our document's FSSpec info, its
  2416. // title and its window's title.
  2417.  
  2418.             if (err == noErr)
  2419.                 err = ResError();
  2420.  
  2421.             if (err) return err;
  2422.  
  2423.             BlockMove(&sfReply.sfFile, docFSSpec, sizeof(FSSpec));
  2424.             BlockMove(&sfReply.sfFile.name, myDocument->documentTitle,
  2425.                       (long) sfReply.sfFile.name[0] +1);
  2426.             
  2427.             SetWTitle(myDocument->documentWindow, myDocument->documentTitle);
  2428.         }
  2429.  
  2430. // Open the file's data fork and resource fork.
  2431.  
  2432.         err = FSpOpenDF(docFSSpec, fsRdWrPerm, &dataRefNum);
  2433.  
  2434.         if (err == noErr)
  2435.         {
  2436.             resRefNum = HOpenResFile(docFSSpec->vRefNum, docFSSpec->parID,
  2437.                                      docFSSpec->name, fsRdWrPerm);
  2438.             err = ResError();
  2439.         }
  2440.  
  2441. // Store the document's page-to-format correspondences, then flatten the
  2442. // job to disk.
  2443.  
  2444.         if (err == noErr)
  2445.         {
  2446.             err = MySaveFormatRefs(myDocument);
  2447.  
  2448.             if (err == noErr)
  2449.                 err = MySaveJobInDataFork(myDocument, dataRefNum);
  2450.         }
  2451.  
  2452.         if (err == noErr)
  2453.         {
  2454.  
  2455. // Now write out the data for our document's pages.
  2456.             
  2457.             /* 
  2458.                 Place your application-specific code here to save 
  2459.                 other data associated with the document.
  2460.                 .
  2461.                 .
  2462.                 .
  2463.             */
  2464.         }
  2465.  
  2466. // Close the data and resource forks of this document.
  2467.  
  2468.         if (dataRefNum != -1) FSClose(dataRefNum);
  2469.         if (resRefNum  != -1) CloseResFile(resRefNum);
  2470.     }
  2471.         
  2472.     UseResFile(oldResFile);
  2473.     return err;
  2474. }
  2475.  
  2476.  
  2477. // This routine is called to flatten a job to disk.  We're passed
  2478. // the refNum of the open data fork to write to.
  2479.  
  2480. OSErr MySaveJobInDataFork(MyDocumentPtr myDocument, short dataRefNum)
  2481. {
  2482.     OSErr    err;
  2483.  
  2484. // Reset the file's position to the beginning of the data fork, and
  2485. // then write the flattened job there.
  2486.  
  2487.     err = SetFPos(dataRefNum, fsFromStart, 0);
  2488.     
  2489.     if (err == noErr)
  2490.     {
  2491.         GXFlattenJob(myDocument->documentJob,
  2492.                    (gxPrintingFlattenProc) MyFlattenJobProc,
  2493.                    (void *) dataRefNum);
  2494.  
  2495.         err = GXGetJobError(myDocument->documentJob);
  2496.     }
  2497.     
  2498.     return err;
  2499. }
  2500.  
  2501.  
  2502. // This routine is a PrintingFlattenProc which flattens a job
  2503. // and writes it to the passed data fork.
  2504.  
  2505. OSErr MyFlattenJobProc(long dataSize, void *data, void *dataRefNum)
  2506. {
  2507.     long    count = dataSize;
  2508.  
  2509.     return FSWrite((short) dataRefNum, &count, data);
  2510. }
  2511.  
  2512.  
  2513. // This routine is called to unflatten a job from disk.  We're passed
  2514. // the refNum of the open data fork to read from.
  2515.  
  2516. OSErr MyLoadJobFromDataFork(MyDocumentPtr myDocument, short dataRefNum)
  2517. {
  2518.     OSErr    err;
  2519.  
  2520. // Reset the file's position to the beginning of the data fork, and
  2521. // then read and unflatten the job from there.
  2522.  
  2523.     err = SetFPos(dataRefNum, fsFromStart, 0);
  2524.     
  2525.     if (err == noErr)
  2526.     {
  2527.         GXUnflattenJob(myDocument->documentJob,
  2528.                      (gxPrintingFlattenProc) MyUnflattenJobProc,
  2529.                      (void *) dataRefNum);
  2530.  
  2531.         err = GXGetJobError(myDocument->documentJob);
  2532.     }
  2533.     
  2534.     return err;
  2535. }
  2536.  
  2537.  
  2538. // This routine is a PrintingFlattenProc which reads and unflattens
  2539. // a job in the passed data fork.
  2540.  
  2541. OSErr MyUnflattenJobProc(long dataSize, void *data, void *dataRefNum)
  2542. {
  2543.     long    count = dataSize;
  2544.  
  2545.     return FSRead((short) dataRefNum, &count, data);
  2546. }
  2547.  
  2548.  
  2549. // This routine opens a document and loads its previously saved job,
  2550. // reassociating any formats that the job contains.
  2551.  
  2552. OSErr MyOpenDocument(MyDocumentPtr myDocument)
  2553. {
  2554.     OSErr                err;
  2555.     Handle                theJobData;
  2556.     short                oldResFile, dataRefNum = -1, resRefNum = -1;
  2557.     StandardFileReply    sfReply;
  2558.     SFTypeList            myTypeList;
  2559.  
  2560. // Let the user select a document to open.
  2561.  
  2562.     oldResFile = CurResFile();
  2563.     
  2564.     myTypeList[0] = kMyDocType;
  2565.     StandardGetFile(nil, 1, myTypeList, &sfReply);
  2566.  
  2567.     if (!sfReply.sfGood)
  2568.         return noErr;
  2569.  
  2570. // Open the selected file's data fork and resource fork.
  2571.  
  2572.     err = FSpOpenDF(&sfReply.sfFile, fsRdWrPerm, &dataRefNum);
  2573.  
  2574.     if (err == noErr)
  2575.     {
  2576.         resRefNum = HOpenResFile(sfReply.sfFile.vRefNum, sfReply.sfFile.parID,
  2577.                                  sfReply.sfFile.name, fsRdPerm);
  2578.         err = ResError();
  2579.     }
  2580.  
  2581. // If we're successful in opening the file, set our document's FSSpec info, its
  2582. // title, and its window's title.
  2583.  
  2584.     if (err == noErr)
  2585.         err = ResError();
  2586.  
  2587.     if (err) return err;
  2588.  
  2589.     BlockMove(&sfReply.sfFile, &myDocument->documentFSSpec, sizeof(FSSpec));
  2590.     BlockMove(&sfReply.sfFile.name, myDocument->documentTitle,
  2591.               (long) sfReply.sfFile.name[0] +1);
  2592.     
  2593.     SetWTitle(myDocument->documentWindow, myDocument->documentTitle);
  2594.  
  2595. // If there's a job resource saved, load it and unflatten it.
  2596.  
  2597.     UseResFile(resRefNum);
  2598.     theJobData = Get1Resource(kMyJobType, kMyJobID);
  2599.  
  2600.     if (theJobData != nil)
  2601.     {
  2602.         GXUnflattenJobFromHdl(myDocument->documentJob, theJobData);
  2603.         err = GXGetJobError(myDocument->documentJob);
  2604.         ReleaseResource(theJobData);
  2605.     }
  2606.  
  2607. // Set up the new format references for each page.
  2608.                 
  2609.     if (err == noErr)
  2610.         err = MyAdjustFormats(myDocument);
  2611.  
  2612. // Now load the data for our document's pages.
  2613.                 
  2614.     /* 
  2615.         Place your application-specific code here to load 
  2616.         other data associated with the document.
  2617.         .
  2618.         .
  2619.         .
  2620.     */
  2621.  
  2622. // Close the data and resource forks of this document.
  2623.  
  2624.     if (dataRefNum != -1) FSClose(dataRefNum);
  2625.     if (resRefNum  != -1) CloseResFile(resRefNum);
  2626.  
  2627.     UseResFile(oldResFile);
  2628.     return err;
  2629. }
  2630.  
  2631.  
  2632. // This routine opens a document and loads its previously saved job
  2633. // from the data fork, reassociating any formats that the job contains.
  2634.  
  2635. OSErr MyOpenDocument2(MyDocumentPtr myDocument)
  2636. {
  2637.     OSErr                err;
  2638.     short                oldResFile, dataRefNum = -1, resRefNum = -1;
  2639.     StandardFileReply    sfReply;
  2640.     SFTypeList            myTypeList;
  2641.  
  2642. // Let the user select a document to open.
  2643.  
  2644.     oldResFile = CurResFile();
  2645.     
  2646.     myTypeList[0] = kMyDocType;
  2647.     StandardGetFile(nil, 1, myTypeList, &sfReply);
  2648.  
  2649.     if (!sfReply.sfGood)
  2650.         return noErr;
  2651.  
  2652. // Open the selected file's data fork and resource fork.
  2653.  
  2654.     err = FSpOpenDF(&sfReply.sfFile, fsRdWrPerm, &dataRefNum);
  2655.  
  2656.     if (err == noErr)
  2657.     {
  2658.         resRefNum = HOpenResFile(sfReply.sfFile.vRefNum, sfReply.sfFile.parID,
  2659.                                  sfReply.sfFile.name, fsRdPerm);
  2660.         err = ResError();
  2661.     }
  2662.  
  2663. // If we're successful in opening the file, set our document's FSSpec info, its
  2664. // title, and its window's title.
  2665.  
  2666.     if (err) return err;
  2667.  
  2668.     BlockMove(&sfReply.sfFile, &myDocument->documentFSSpec, sizeof(FSSpec));
  2669.     BlockMove(&sfReply.sfFile.name, myDocument->documentTitle,
  2670.               (long) sfReply.sfFile.name[0] +1);
  2671.     
  2672.     SetWTitle(myDocument->documentWindow, myDocument->documentTitle);
  2673.  
  2674. // Load and unflatten the job from the data fork.
  2675.  
  2676.     err = MyLoadJobFromDataFork(myDocument, dataRefNum);
  2677.  
  2678.     if (err == noErr)
  2679.     {
  2680.     
  2681. // Any format references saved with a document are no longer valid,
  2682. // so we need to adjust them.
  2683.                     
  2684.         UseResFile(resRefNum);
  2685.     
  2686.         if (err == noErr)
  2687.             err = MyAdjustFormats(myDocument);
  2688.  
  2689. // Now load the data for our document's pages.
  2690.                 
  2691.         /* 
  2692.             Place your application-specific code here to load 
  2693.             other data associated with the document.
  2694.             .
  2695.             .
  2696.             .
  2697.         */
  2698.  
  2699. // Close the data and resource forks of this document.
  2700.  
  2701.     }
  2702.  
  2703.     if (dataRefNum != -1) FSClose(dataRefNum);
  2704.     if (resRefNum  != -1) CloseResFile(resRefNum);
  2705.  
  2706.     UseResFile(oldResFile);
  2707.     return err;
  2708. }
  2709.  
  2710.  
  2711. // This routine opens a document and loads its previously saved job,
  2712. // reassociating any formats that the job contains.  It's just like
  2713. // MyOpenDocument, but it opens the indicated file and doesn't
  2714. // present a file dialog.
  2715.  
  2716. OSErr MyFSOpenDocument(MyDocumentPtr myDocument, FSSpec *docFSSpec)
  2717. {
  2718.     OSErr        err;
  2719.     Handle        theJobData;
  2720.     short        oldResFile, dataRefNum = -1, resRefNum = -1;
  2721.  
  2722.     oldResFile = CurResFile();
  2723.  
  2724. // Open the selected file's data fork and resource fork.
  2725.  
  2726.     err = FSpOpenDF(docFSSpec, fsRdWrPerm, &dataRefNum);
  2727.  
  2728.     if (err == noErr)
  2729.     {
  2730.         resRefNum = HOpenResFile(docFSSpec->vRefNum, docFSSpec->parID, docFSSpec->name, fsRdPerm);
  2731.         err = ResError();
  2732.     }
  2733.  
  2734. // If we're successful in opening the file, set our document's FSSpec info, its
  2735. // title, and its window's title.
  2736.  
  2737.     if (err == noErr)
  2738.         err = ResError();
  2739.  
  2740.     if (err) return err;
  2741.  
  2742.     BlockMove(docFSSpec, &myDocument->documentFSSpec, sizeof(FSSpec));
  2743.     BlockMove(docFSSpec->name, myDocument->documentTitle, (long) docFSSpec->name[0] +1);
  2744.     SetWTitle(myDocument->documentWindow, myDocument->documentTitle);
  2745.  
  2746. // If there's a job resource saved, load it and unflatten it.
  2747.  
  2748.     UseResFile(resRefNum);
  2749.     theJobData = Get1Resource(kMyJobType, kMyJobID);
  2750.  
  2751.     if (theJobData != nil)
  2752.     {
  2753.         GXUnflattenJobFromHdl(myDocument->documentJob, theJobData);
  2754.         err = GXGetJobError(myDocument->documentJob);
  2755.         ReleaseResource(theJobData);
  2756.     }
  2757.  
  2758. // Any format references saved with a document are no longer valid,
  2759. // so we need to adjust them.
  2760.                 
  2761.     if (err == noErr)
  2762.         err = MyAdjustFormats(myDocument);
  2763.  
  2764. // Now load the data for our document's pages.
  2765.                 
  2766.     /* 
  2767.         Place your application-specific code here to load 
  2768.         other data associated with the document.
  2769.         .
  2770.         .
  2771.         .
  2772.     */
  2773.  
  2774. // Close the data and resource forks of this document.
  2775.  
  2776.     if (dataRefNum != -1) FSClose(dataRefNum);
  2777.     if (resRefNum  != -1) CloseResFile(resRefNum);
  2778.  
  2779.     UseResFile(oldResFile);
  2780.     return err;
  2781. }
  2782.  
  2783.  
  2784. // This routine saves page format indices for a document.  We'll store
  2785. // this info in the job's default format's collection.  We use this
  2786. // information to "reconstruct" the document the next time we
  2787. // open it.  This routine is called when we save a document, before we
  2788. // have flattened the document's job.
  2789. //
  2790.  
  2791. OSErr MySaveFormatRefs(MyDocumentPtr myDocument)
  2792. {
  2793.     OSErr                err = noErr;
  2794.     Handle                theFormatIdxList;
  2795.     Collection            fmtCollection;
  2796.     gxFormat            defaultFmt;
  2797.  
  2798. // If we have any pages in this document, create a handle containing all of the
  2799. // page format indices.
  2800.  
  2801.     if (myDocument->numPages > 0)
  2802.     {
  2803.  
  2804. // Get the job's default format's collection, and if we've already
  2805. // stored a page-to-format correspondence item in it, remove it.
  2806.  
  2807.         defaultFmt = GXGetJobFormat(myDocument->documentJob, 1);
  2808.         fmtCollection = GXGetFormatCollection(defaultFmt);
  2809.  
  2810.         if (fmtCollection != nil)
  2811.             RemoveCollectionItem(fmtCollection, kMyFormatInfoType, kMyFormatInfoTagID);
  2812.  
  2813. // Create a list of page-to-format correspondences for the current document.
  2814. // If there are no errors, add the item to the job's default format's
  2815. // collection, for later retrieval.
  2816.  
  2817.  
  2818.         err = MyCreateFormatIndexList(myDocument, &theFormatIdxList);
  2819.  
  2820.         if (err == noErr)
  2821.         {
  2822.             HLock(theFormatIdxList);
  2823.             err = AddCollectionItem(fmtCollection,
  2824.                                     kMyFormatInfoType,
  2825.                                     kMyFormatInfoTagID,
  2826.                                     GetHandleSize(theFormatIdxList),
  2827.                                     *theFormatIdxList);
  2828.     
  2829.             DisposHandle(theFormatIdxList);
  2830.         }
  2831.     }
  2832.  
  2833.     return err;
  2834. }
  2835.  
  2836.  
  2837. // This routine stores the index of each page's format in a handle.
  2838. // The index of page #1's format will go in the first longword of
  2839. // theFormatIdxList handle, the index of the next page's format will
  2840. // go in the next longword, and so on.  The handle is created and
  2841. // returned to the caller.
  2842.  
  2843. OSErr MyCreateFormatIndexList(MyDocumentPtr myDocument, Handle *theFormatIdxList)
  2844. {
  2845.     OSErr        err;
  2846.     long        fmtIdx, pg, *idxList;
  2847.     gxFormat    curFormat;
  2848.  
  2849. // Create a handle large enough to hold all of our entries.  We use
  2850. // NewHandleClear so that all of our indices are initialized to 0
  2851. // (an invalid format index).  Since our application stores a nil
  2852. // format reference for any page which uses the job's default format,
  2853. // this allows us to indicate these "nil references" by an index of
  2854. // 0 in our collection item.  When we re-open the document, we'll
  2855. // know that an index of 0 means "Use the job's default format."
  2856.  
  2857.     *theFormatIdxList = NewHandleClear(sizeof(long) * (myDocument->numPages));
  2858.     err = MemError();
  2859.  
  2860. // If there aren't any errors, go through every format in the document's
  2861. // job.  If the format is used by any pages of our document, store the
  2862. // format's index in those page entries of theFormatIdxList.  We skip format
  2863. // #1, since that's the job format (and we're storing nil for the index in
  2864. // this case).  Because we created the handle with NewHandleClear, nil will
  2865. // already be stored in any entries we don't change.
  2866.  
  2867.     if (err == noErr)
  2868.     {
  2869.         HLock(*theFormatIdxList);
  2870.         idxList = (long *) **theFormatIdxList;
  2871.         
  2872.         for (fmtIdx = 2; fmtIdx <= GXCountJobFormats(myDocument->documentJob); fmtIdx++)
  2873.         {
  2874.             curFormat = GXGetJobFormat(myDocument->documentJob, fmtIdx);
  2875.     
  2876.             for (pg = 1; pg <= myDocument->numPages; pg++)
  2877.                 if (myDocument->pageFormat[pg -1] == curFormat)
  2878.                     idxList[pg -1] = fmtIdx;
  2879.         }
  2880.         
  2881.         HUnlock(*theFormatIdxList);
  2882.     }
  2883.  
  2884.     return err;
  2885. }
  2886.  
  2887.  
  2888. // This routine associates new format references with a document, based
  2889. // upon the format indices which were saved with the document.
  2890. // The routine is called when we open a document.
  2891. //
  2892. // The format references will be stored in the passed MyDocumentRec
  2893. // structure.
  2894.  
  2895. OSErr MyAdjustFormats(MyDocumentPtr myDocument)
  2896. {
  2897.     OSErr        err = noErr;
  2898.     Handle        theFormatIdxList = nil;
  2899.     gxFormat    theFormat, defaultFmt;
  2900.     long        pg, numPages, fmtIdx, *idxList, idx, listSize, attribs;
  2901.     Collection    fmtCollection;
  2902.  
  2903. // Get the job's default format's collection, and look for one of our
  2904. // page-to-format correspondence items in it.
  2905.  
  2906.     defaultFmt = GXGetJobFormat(myDocument->documentJob, 1);
  2907.     fmtCollection = GXGetFormatCollection(defaultFmt);
  2908.  
  2909.  
  2910. // Load our item containing our page-to-format correspondences.
  2911. // We do this in two passes.  First we determine if the item
  2912. // exists, and if so, get its size.  Next we create a handle
  2913. // to hold the item (if it exists), and then actually retrieve it.
  2914. // Because there will be one longword entry for each page of our
  2915. // document, we can determine the number of pages in the document.
  2916.  
  2917.     err = GetCollectionItemInfo(fmtCollection, kMyFormatInfoType,
  2918.                                 kMyFormatInfoTagID, &idx, &listSize, &attribs);
  2919.  
  2920.     if (err == noErr)
  2921.         theFormatIdxList = NewHandle(listSize);
  2922.  
  2923.     if (theFormatIdxList != nil)
  2924.     {
  2925.         HLock(theFormatIdxList);
  2926.  
  2927.         err = GetCollectionItem(fmtCollection, kMyFormatInfoType,
  2928.                                   kMyFormatInfoTagID, nil, *theFormatIdxList);
  2929.  
  2930.         numPages = listSize / sizeof(long);
  2931.  
  2932.  
  2933. // We TEMPORARILY cheat here and rebuild the page rather than load and save the shapes.
  2934.  
  2935.         for (pg = 1; !err && (pg <= numPages); pg++)
  2936.         {
  2937.             err = MyInsertPage(myDocument);
  2938.             myDocument->curPage = pg;
  2939.         }
  2940.         myDocument->curPage = 1;
  2941.  
  2942. // Loop through each saved index.  The way we saved them, the first is for
  2943. // page 1, the second is for page 2, and so on.  We need to call
  2944. // GetJobFormat for each saved index.  If the index is nil, that's just
  2945. // our way of saying "use the job format."  In that case, we don't call
  2946. // GetJobFormat, we just store nil for the page's format.  Store
  2947. // the format references as they're processed.  When we're done, throw
  2948. // away the handle we created.
  2949.  
  2950.         idxList = (long *) *theFormatIdxList;
  2951.         
  2952.         for (pg = 1; pg <= numPages; pg++)
  2953.         {
  2954.             fmtIdx = idxList[pg -1];
  2955.             
  2956.             if (fmtIdx != 0)
  2957.                 theFormat = GXGetJobFormat(myDocument->documentJob, fmtIdx);
  2958.             else
  2959.                 theFormat = nil;
  2960.  
  2961.             myDocument->pageFormat[pg -1] = theFormat;
  2962.         }
  2963.  
  2964.         DisposHandle(theFormatIdxList);
  2965.     }
  2966.  
  2967.     return err;
  2968. }
  2969.  
  2970.  
  2971. // This routine converts an old-style (TPrint) print record into a QuickDraw
  2972. // GX job.  We use this routine when we're opening an old document that
  2973. // had a print record saved with it rather than a job.  The old-style
  2974. // print record is passed in hPrint.
  2975.  
  2976. OSErr MyPrintRecordToJob(MyDocumentPtr myDocument, THPrint hPrint)
  2977. {
  2978.  
  2979. // Convert the print record and store its settings in
  2980. // the passed job.  Then dispose of its handle.
  2981.  
  2982.     GXConvertPrintRecord(myDocument->documentJob, hPrint);
  2983.     DisposeHandle((Handle) hPrint);
  2984.  
  2985.     return GXGetJobError(myDocument->documentJob);
  2986. }
  2987.  
  2988.  
  2989. // Insert a page at the current display location.
  2990.  
  2991. OSErr MyInsertPage(MyDocumentPtr myDocument)
  2992. {
  2993.     gxGraphicsError    grErr;
  2994.     long            pg, curPage;
  2995.     Str255            pStr;
  2996.     gxRectangle        windowBounds;
  2997.     gxShape            txtShape;
  2998.     
  2999.     curPage = myDocument->curPage;
  3000.     
  3001.     if (myDocument->numPages != 0)
  3002.         for (pg = myDocument->numPages; pg > curPage; pg--)
  3003.         {
  3004.             myDocument->documentPage[pg] = myDocument->documentPage[pg -1];
  3005.             myDocument->pageFormat[pg] = myDocument->pageFormat[pg -1];
  3006.         }
  3007.     else
  3008.         curPage = 0;
  3009.     
  3010.     ++curPage;
  3011.     
  3012.     pStr[0] = sprintf((char *) &pStr[1], "%s%i", "Reference ID #", myDocument->numPages +1);
  3013.     txtShape = GXNewText((long) pStr[0], (const unsigned char *) &pStr[1], nil);
  3014.  
  3015.     SetShapeCommonFont(txtShape, timesFont);
  3016.     GXSetShapeTextSize(txtShape, ff(24));
  3017.     GXSetShapeAttributes(txtShape, (GXGetShapeAttributes(txtShape)) | gxMapTransformShape);
  3018.     GXSetShapeViewPorts(txtShape, 1, &myDocument->documentViewPort);
  3019.  
  3020.     windowBounds.left = ff(0);
  3021.     windowBounds.top = ff(0);
  3022.     windowBounds.right = ff(370);
  3023.     windowBounds.bottom = ff(440);
  3024.  
  3025.     CenterShape(txtShape, &windowBounds);
  3026.     myDocument->documentPage[curPage -1] = GXNewShape(gxPictureType);
  3027.     GXSetShapeViewPorts(myDocument->documentPage[curPage -1], 1, &myDocument->documentViewPort);
  3028.     GXSetShapeAttributes(myDocument->documentPage[curPage -1],
  3029.                          (GXGetShapeAttributes(myDocument->documentPage[curPage -1])) | gxUniqueItemsShape);
  3030.     GXSetPictureParts(myDocument->documentPage[curPage -1], 0, 0, 1, &txtShape, nil, nil, nil);
  3031.     GXDisposeShape(txtShape);
  3032.  
  3033.     myDocument->pageFormat[curPage -1] = nil;
  3034.  
  3035.     grErr = GXGetGraphicsError(nil);
  3036.     
  3037.     if (grErr == noErr)
  3038.     {
  3039.         myDocument->curPage = curPage;
  3040.         ++myDocument->numPages;
  3041.         InvalRect(&(myDocument->documentWindow)->portRect);
  3042.     }
  3043.     else
  3044.         GXDisposeShape(myDocument->documentPage[curPage -1]);
  3045.  
  3046.     return (OSErr) grErr;
  3047. }
  3048.  
  3049.  
  3050. // Delete the current page of a document and free up any memory we
  3051. // allocated for it.
  3052.  
  3053. OSErr MyDeletePage(MyDocumentPtr myDocument)
  3054. {    
  3055.     OSErr        err;
  3056.     long        curPage, pg;
  3057.  
  3058. // Dispose of the current page's shape and format.  If the page format is nil,
  3059. // this indicates that the page used the document's job format.  In this case,
  3060. // there is no format to dispose.
  3061.  
  3062.     curPage = myDocument->curPage;
  3063.     GXDisposeShape(myDocument->documentPage[curPage -1]);
  3064.  
  3065.     if (myDocument->pageFormat[curPage -1] != nil)
  3066.         GXDisposeFormat(myDocument->pageFormat[curPage -1]);
  3067.  
  3068.     /*
  3069.         Place any application-specific code to delete a page here.
  3070.  
  3071.         .
  3072.         .
  3073.         .
  3074.  
  3075.     */
  3076.  
  3077. // We shift all pages after this one down a page to fill the gap created
  3078. // by this deletion.  When finished, we decrement the number of pages in
  3079. // our document.
  3080.  
  3081.     if (myDocument->numPages != 0)
  3082.         for (pg = curPage; pg < myDocument->numPages; pg++)
  3083.         {
  3084.             myDocument->documentPage[pg -1] = myDocument->documentPage[pg];
  3085.             myDocument->pageFormat[pg -1] = myDocument->pageFormat[pg];
  3086.         }
  3087.  
  3088.     --myDocument->numPages;
  3089.  
  3090. // If the "current page" value is now invalid for this document, decrement it to
  3091. // reference the previous page, if any.  Invalidate the window so that the document
  3092. // is updated on screen.  Finally, check for errors and return.
  3093.  
  3094.     if (curPage > myDocument->numPages)
  3095.         --myDocument->curPage;
  3096.  
  3097.     InvalRect(&(myDocument->documentWindow)->portRect);
  3098.  
  3099.     err = GXGetJobError(myDocument->documentJob);
  3100.     if (err == noErr) err = GXGetGraphicsError(nil);
  3101.  
  3102.     return err;
  3103. }
  3104.  
  3105.  
  3106. // MyBackPage moves us back a page in the document.
  3107.  
  3108. void MyBackPage(WindowPtr whichWindow)
  3109. {
  3110.     MyDocumentPtr    myDocument;
  3111.  
  3112.     if (((WindowPeek) whichWindow)->windowKind != userKind) return;
  3113.     myDocument = (MyDocumentPtr) GetWRefCon(whichWindow);
  3114.  
  3115.     if (myDocument->curPage > 1)
  3116.     {
  3117.         --myDocument->curPage;
  3118.         InvalRect(&whichWindow->portRect);
  3119.     }
  3120. }
  3121.  
  3122.  
  3123. // MyAheadPage moves us forward a page in the document.
  3124.  
  3125. void MyAheadPage(WindowPtr whichWindow)
  3126. {
  3127.     MyDocumentPtr    myDocument;
  3128.  
  3129.     if (((WindowPeek) whichWindow)->windowKind != userKind) return;
  3130.     myDocument = (MyDocumentPtr) GetWRefCon(whichWindow);
  3131.  
  3132.     if (myDocument->curPage < myDocument->numPages)
  3133.     {
  3134.         ++myDocument->curPage;
  3135.         InvalRect(&whichWindow->portRect);
  3136.     }
  3137. }
  3138.  
  3139.  
  3140. // This routine adds a form consisting of a rectangle
  3141. // to the current page's format.
  3142.  
  3143. OSErr MyAddFormatForm(MyDocumentPtr myDocument)
  3144. {    
  3145.     OSErr            err;
  3146.     long            curPage;
  3147.     gxFormat        theFormat;
  3148.     gxShape            rectShape;
  3149.     gxRectangle        pageRect;
  3150.  
  3151. // Get the current format.  If it's nil, this means we're
  3152. // using the job's default format.
  3153.  
  3154.     curPage = myDocument->curPage;
  3155.     theFormat = myDocument->pageFormat[curPage -1];
  3156.  
  3157.     if (theFormat == nil)
  3158.         theFormat = GXGetJobFormat(myDocument->documentJob, 1);
  3159.  
  3160. // Create a rectangle shape to use as the format's form.
  3161. // We'll make the rectangle's frame be the imageable area
  3162. // of the page.
  3163.  
  3164.     GXGetFormatDimensions(theFormat, &pageRect, nil);
  3165.     rectShape = GXNewRectangle(&pageRect);
  3166.     
  3167.     GXSetShapeBounds(rectShape, &pageRect);
  3168.     GXSetShapePen(rectShape, ff(3));
  3169.     GXInsetShape(rectShape, ff(3));
  3170.     GXSetShapeFill(rectShape, gxClosedFrameFill);
  3171.  
  3172.     err = (OSErr) GXGetGraphicsError(nil);
  3173.  
  3174. // Set the format's form to our new shape (it must be a
  3175. // picture), check for errors, then dispose of the shape.
  3176.  
  3177.     if (err == noErr)
  3178.     {
  3179.         GXSetShapeType(rectShape, gxPictureType);
  3180.         GXSetFormatForm(theFormat, rectShape, nil);
  3181.         err = GXGetJobError(myDocument->documentJob);
  3182.     }
  3183.  
  3184.     GXDisposeShape(rectShape);
  3185.  
  3186.     return err;
  3187. }
  3188.  
  3189.  
  3190. // This routine removes the current page's format form, if any.
  3191.  
  3192. OSErr MyRemoveFormatForm(MyDocumentPtr myDocument)
  3193. {    
  3194.     long        curPage;
  3195.     gxFormat    theFormat;
  3196.  
  3197. // Get the current format.  If it's nil, this means we're
  3198. // using the job's default format.
  3199.  
  3200.     curPage = myDocument->curPage;
  3201.     theFormat = myDocument->pageFormat[curPage -1];
  3202.  
  3203.     if (theFormat == nil)
  3204.         theFormat = GXGetJobFormat(myDocument->documentJob, 1);
  3205.  
  3206. // Set the format's form and mask to nil.
  3207.  
  3208.     GXSetFormatForm(theFormat, nil, nil);
  3209.     return GXGetJobError(myDocument->documentJob);
  3210. }
  3211.  
  3212.  
  3213. // This routine moves a page format to another job.  We use this routine
  3214. // when we move a page from one document to another, if no other page in
  3215. // the original document currently uses the source page's format.
  3216. //
  3217. // srcPage and srcDocument represent the page's location in the original
  3218. // document, destPage and destDocument refer to the new location and
  3219. // document.  There is initially no page format for the destination page.
  3220.  
  3221. OSErr MyMoveFormatToJob(long srcPage, MyDocumentPtr srcDocument, long destPage, MyDocumentPtr destDocument)
  3222. {
  3223.     OSErr        err;
  3224.     gxFormat    srcPgFormat, destPgFormat;
  3225.     
  3226. // Get the indicated source page format.  If the reference is nil, this
  3227. // indicates that we're using the source document's default job format.
  3228. // In this case, create a destination format from the source job and
  3229. // use that.
  3230.  
  3231.     srcPgFormat = srcDocument->pageFormat[srcPage];
  3232.     
  3233.     if (srcPgFormat == nil)
  3234.         srcPgFormat = GXNewFormat(srcDocument->documentJob);
  3235.     
  3236. // Create a new destination format and copy the source format to it.  When
  3237. // done, dispose of the source format and clear out the source page's reference.
  3238.  
  3239.     destPgFormat = GXNewFormat(destDocument->documentJob);
  3240.     GXCopyFormat(srcPgFormat, destPgFormat);
  3241.     GXDisposeFormat(srcPgFormat);
  3242.     srcDocument->pageFormat[srcPage] = nil;
  3243.  
  3244. // If there were no errors, store the destination page's format reference.
  3245.  
  3246.     err = GXGetJobError(srcDocument->documentJob);
  3247.  
  3248.     if (err == noErr)
  3249.         err = GXGetJobError(destDocument->documentJob);
  3250.     
  3251.     if (err == noErr)
  3252.         destDocument->pageFormat[destPage] = destPgFormat;
  3253.  
  3254.     return err;
  3255. }
  3256.  
  3257.  
  3258. // This function takes the job associated with srcDocument and copies
  3259. // its information to destDocument.  This has the effect of copying
  3260. // the formatting and job-specific information in the source document
  3261. // to the destination document.
  3262. //
  3263. // Note that this changes any formats that the destination job
  3264. // originally had (and the old references become invalid).
  3265.  
  3266. OSErr MyCopyJobToDoc(MyDocumentPtr srcDocument, MyDocumentPtr destDocument)
  3267. {
  3268.     long    pg;
  3269.  
  3270. // Copy the job information, invalidate any old format references,
  3271. // and return any error codes.
  3272.  
  3273.     GXCopyJob(srcDocument->documentJob, destDocument->documentJob);
  3274.     
  3275.     for (pg = 1; pg <= destDocument->numPages; pg++)
  3276.         destDocument->pageFormat[pg -1] = nil;
  3277.     
  3278.     return GXGetJobError(srcDocument->documentJob);
  3279. }
  3280.  
  3281.  
  3282. // This routine stores a refCon in the job, and then retrieves it.
  3283. // we compare the 2 values to see if they're the same, which they'd
  3284. // better be.
  3285.  
  3286. OSErr MyJobRefConTest(MyDocumentPtr myDocument)
  3287. {
  3288.     Str255    pStr;
  3289.     MyDocumentPtr    beforePtr, afterPtr;
  3290.  
  3291. // Store the document pointer, set the refCon field, retrieve the refCon,
  3292. // and compare the two values.
  3293.  
  3294.     beforePtr = myDocument;
  3295.     GXSetJobRefCon(myDocument->documentJob, myDocument);
  3296.     afterPtr = GXGetJobRefCon(myDocument->documentJob);
  3297.  
  3298.     pStr[0] = sprintf((char *) &pStr[1], "These better be the same… %p == %p?", beforePtr, afterPtr);
  3299.     MyDisplayInfo(pStr);
  3300.  
  3301.     return GXGetJobError(myDocument->documentJob);
  3302. }
  3303.  
  3304.  
  3305. // This function returns the number of pages in the indicated
  3306. // print file.
  3307.  
  3308. OSErr MyGetPrintFilePages(FSSpec *printFSSpec, long *numCopies)
  3309. {
  3310.     OSErr            err;
  3311.     gxPrintFile        thePrintFile;
  3312.     gxJob            fileJob;
  3313.  
  3314. // Create a new job for GXOpenPrintFile, then open the print file, get the
  3315. // number of pages in it, close it, and check for errors.  Finally,
  3316. // dispose of the temporary job we created and return.
  3317.  
  3318.     err = GXNewJob(&fileJob);
  3319.     
  3320.     if (err == noErr)
  3321.     {
  3322.         thePrintFile = GXOpenPrintFile(fileJob, printFSSpec, fsCurPerm);
  3323.         *numCopies = GXCountPrintFilePages(thePrintFile);
  3324.         GXClosePrintFile(thePrintFile);
  3325.  
  3326.         err = GXGetJobError(fileJob);
  3327.         GXDisposeJob(fileJob);
  3328.     }
  3329.     
  3330.     return err;
  3331. }
  3332.  
  3333.  
  3334. // This routine reads a page from a print file and returns its
  3335. // corresponding format and shape.
  3336.  
  3337. OSErr MyReadPrintFilePage(MyDocumentPtr myDocument, FSSpec *printFSSpec,
  3338.                           long whichPg, gxFormat *pgFormat, gxShape *pgShape)
  3339. {
  3340.     gxPrintFile    thePrintFile;
  3341.  
  3342. // Open the print file, read the page, close the file, and check for errors.
  3343.  
  3344.     thePrintFile = GXOpenPrintFile(myDocument->documentJob, printFSSpec, fsCurPerm);
  3345.     GXReadPrintFilePage(thePrintFile, whichPg, 1, &myDocument->documentViewPort, pgFormat, pgShape);
  3346.     GXClosePrintFile(thePrintFile);
  3347.  
  3348.     return GXGetJobError(myDocument->documentJob);
  3349. }
  3350.  
  3351.  
  3352. // This routine creates a new paperType based on the job passed.
  3353.  
  3354. OSErr MyCreatePaperType(MyDocumentPtr myDocument, Str31 paperName, gxRectangle *pageSize,
  3355.                         gxRectangle *paperSize, gxPaperType *newPaperType)
  3356. {
  3357.     *newPaperType = GXNewPaperType(myDocument->documentJob, paperName, pageSize, paperSize);
  3358.  
  3359.     return GXGetJobError(myDocument->documentJob);
  3360. }
  3361.  
  3362.  
  3363. // This is a FormatProc that looks at the mapping of each format
  3364. // it's passed.
  3365.  
  3366. pascal gxLoopStatus MyCheckMappingProc(gxFormat aFormat, void *theMapping)
  3367. {
  3368.  
  3369. // Get the mapping for the current format, check it out,
  3370. // and keep looping until all formats have been accessed.
  3371.  
  3372.     GXGetFormatMapping(aFormat, (gxMapping *) theMapping);
  3373.         
  3374.     /*    Below, your application could adjust rulers, or do some
  3375.         other useful thing based on each format's mapping.
  3376.             .
  3377.             .
  3378.             .
  3379.     */
  3380.     
  3381.     return gxKeepLooping;
  3382. }
  3383.  
  3384.  
  3385. // This routine passes the format of each page in our
  3386. // document to the "MyCheckMappingProc" FormatProc.
  3387.  
  3388. OSErr MyCheckAllFormatMappings(MyDocumentPtr myDocument)
  3389. {
  3390.     gxMapping        theMapping;
  3391.  
  3392. // Loop through each format, and check its mapping.
  3393.  
  3394.     GXForEachJobFormatDo(myDocument->documentJob, MyCheckMappingProc,
  3395.                          (void *) &theMapping);
  3396.  
  3397.     return GXGetJobError(myDocument->documentJob);
  3398. }
  3399.  
  3400.  
  3401. // This routine returns the format mapping for the indicated
  3402. // page of our document.
  3403.  
  3404. OSErr MyGetFormatMapping(MyDocumentPtr myDocument, long whichPage,
  3405.                          gxMapping *theMapping)
  3406. {
  3407.     gxFormat    pgFormat;
  3408.  
  3409. // Get the current page's format, or the job's default
  3410. // format if we've set this page's format reference to nil
  3411. // to indicate this.
  3412.  
  3413.     pgFormat = myDocument->pageFormat[whichPage -1];
  3414.     
  3415.     if (pgFormat == nil)
  3416.         pgFormat = GXGetJobFormat(myDocument->documentJob, 1);
  3417.  
  3418. // Get the format's mapping.
  3419.  
  3420.     GXGetFormatMapping(pgFormat, theMapping);
  3421.     return GXGetJobError(myDocument->documentJob);
  3422. }
  3423.  
  3424.  
  3425. // This function returns the current "copies" setting from a document's
  3426. // job.  A user sets this value via the print dialog, and it sticks to
  3427. // the job, once set.
  3428. //
  3429. // In the passed document's job, we look for a copiesTag collection
  3430. // item.  If we find one, we return the number of copies stored in it.
  3431.  
  3432. OSErr MyGetJobCopies(MyDocumentPtr myDocument, short *numCopies)
  3433. {
  3434.     OSErr            err;
  3435.     Collection        jobCollection;
  3436.     gxCopiesInfo    theCopiesInfo;
  3437.  
  3438. // Get the job collection, and then look for a copiesTag collection item.
  3439.  
  3440.     jobCollection = GXGetJobCollection(myDocument->documentJob);
  3441.  
  3442.     err = GetCollectionItem(jobCollection,
  3443.                             gxCopiesTag,
  3444.                             gxPrintingTagID,
  3445.                             nil,
  3446.                             &theCopiesInfo);
  3447.  
  3448. // If we found one, extract the number of copies and return it.
  3449.  
  3450.     if (err == noErr)
  3451.         *numCopies = theCopiesInfo.copies;
  3452.  
  3453.     return err;
  3454. }
  3455.  
  3456.  
  3457. // This function displays a dialog showing the name and type of the
  3458. // printer and printer driver that the passed document's job will
  3459. // print to.
  3460.  
  3461. OSErr MyShowJobPrinterInfo(MyDocumentPtr myDocument)
  3462. {
  3463.     OSErr        err;
  3464.     short        itemHit;
  3465.     DialogPtr    msgDlog;
  3466.     GrafPtr        oldPort;
  3467.     gxPrinter    jobPrinter;
  3468.     OSType        deviceOSType, driverOSType;
  3469.     Str255        deviceName, deviceType, driverName, driverType;
  3470.  
  3471. // Load our info dialog.
  3472.  
  3473.     GetPort(&oldPort);
  3474.     msgDlog = GetNewDialog(r_printerInfoDlog, nil, (WindowPtr) -1);
  3475.     err = ResError();
  3476.  
  3477. // Get the current printer for this job.  From that, get the
  3478. // current device name, driver name, device type, and driver type.
  3479.  
  3480.     if (err == noErr)
  3481.     {
  3482.         jobPrinter = GXGetJobOutputPrinter(myDocument->documentJob);
  3483.         
  3484.         GXGetPrinterName(jobPrinter, deviceName);
  3485.         GXGetPrinterDriverName(jobPrinter, driverName);
  3486.         deviceOSType = GXGetPrinterType(jobPrinter);
  3487.         driverOSType = GXGetPrinterDriverType(jobPrinter);
  3488.  
  3489.         err = GXGetJobError(myDocument->documentJob);
  3490.  
  3491. // Since the device and driver type are OSTypes, we need to convert them to
  3492. // Pascal strings for ParamText.  That's what these two lines do.
  3493.     
  3494.         if (err == noErr)
  3495.         {
  3496.             BlockMove(&deviceOSType, &deviceType[1], (long) (deviceType[0] = 4));
  3497.             BlockMove(&driverOSType, &driverType[1], (long) (driverType[0] = 4));
  3498.  
  3499. // Use ParamText to pass the data to our dialog, then display our dialog
  3500. // and set our current port to it.
  3501.     
  3502.             ParamText(deviceName, driverName, deviceType, driverType);
  3503.             SetPort(msgDlog);
  3504.             MyPositionWindow(msgDlog, true, n_dlogLevel);
  3505.  
  3506. // Loop until the user clicks "OK", then reset ParamText and dispose
  3507. // of our dialog.
  3508.     
  3509.             do
  3510.             {
  3511.                 ModalDialog(nil, &itemHit);
  3512.             }
  3513.             while (itemHit != kOKButton);
  3514.     
  3515.             ParamText("\p", "\p", "\p", "\p");
  3516.             DisposDialog(msgDlog);
  3517.         }
  3518.     }
  3519.  
  3520.     SetPort(oldPort);
  3521.     return err;
  3522. }
  3523.  
  3524.  
  3525. // This function displays a dialog showing the highest
  3526. // "square" resolutions for the job's formatting and
  3527. // output printers.
  3528.  
  3529. void MyShowJobPrinterResolution(MyDocumentPtr myDocument)
  3530. {
  3531.     Fixed    hFRes, vFRes, hORes, vORes;
  3532.     Str255    pStr;
  3533.     
  3534.     MyGetFormatDeviceResolution(myDocument->documentJob, &hFRes, &vFRes);
  3535.     MyGetOutputDeviceResolution(myDocument->documentJob, &hORes, &vORes);
  3536.  
  3537.     pStr[0] = sprintf((char *) &pStr[1], "%s%d%s%d%s",
  3538.                       "Formatting printer's res. = ",
  3539.                       FixedToInt(hFRes),
  3540.                       " dpi.\n Output printer's res. = ",
  3541.                       FixedToInt(hORes),
  3542.                       " dpi.");
  3543.  
  3544.     MyDisplayInfo(pStr);
  3545. }
  3546.  
  3547.  
  3548. // This routine returns the highest square resolution of
  3549. // the formatting printer for the specified job.
  3550.  
  3551. void MyGetFormatDeviceResolution(gxJob whichJob, Fixed *hRes, Fixed *vRes)
  3552. {
  3553.     gxPrinter        formatPrinter;
  3554.     long            numViewDevices, idx;
  3555.     gxViewDevice    printerVDev;
  3556.     gxMapping        vDevMapping;
  3557.  
  3558. /*
  3559.     Get the formatting printer, and the number of
  3560.     viewdevices for that printer.
  3561. */
  3562.  
  3563.     *hRes = 0;
  3564.     *vRes = 0;
  3565.  
  3566.     formatPrinter = GXGetJobFormattingPrinter(whichJob);
  3567.     numViewDevices = GXCountPrinterViewDevices(formatPrinter);
  3568.  
  3569. /*
  3570.     Loop through the viewdevices that this printer supports,
  3571.     and get the highest "square" (vertical == horizontal)
  3572.     resolution.
  3573. */
  3574.  
  3575.     for (idx = 1; idx <= numViewDevices; idx++)
  3576.     {
  3577.         printerVDev = GXGetPrinterViewDevice(formatPrinter, idx);
  3578.         GXGetViewDeviceMapping(printerVDev, &vDevMapping);
  3579.  
  3580.         if ((vDevMapping.map[0][0] == vDevMapping.map[1][1]) &&
  3581.             (vDevMapping.map[0][0] > *hRes) && (vDevMapping.map[1][1] > *vRes))
  3582.         {
  3583.             *hRes = vDevMapping.map[0][0];
  3584.             *vRes = vDevMapping.map[1][1];
  3585.         }
  3586.     }
  3587.  
  3588. /*
  3589.     We have only scaling factors (multiples of 72 dpi),
  3590.     so convert them into resolutions.
  3591. */
  3592.  
  3593.     *hRes = FixedMultiply(*hRes, ff(72));
  3594.     *vRes = FixedMultiply(*vRes, ff(72));
  3595. }
  3596.  
  3597.  
  3598. // This routine returns the highest square resolution of
  3599. // the output printer for the specified job.
  3600.  
  3601. void MyGetOutputDeviceResolution(gxJob whichJob, Fixed *hRes, Fixed *vRes)
  3602. {
  3603.     gxPrinter        outputPrinter;
  3604.     long            numViewDevices, idx;
  3605.     gxViewDevice    printerVDev;
  3606.     gxMapping        vDevMapping;
  3607.  
  3608. /*
  3609.     Get the output printer, and the number of
  3610.     viewdevices for that printer.
  3611. */
  3612.  
  3613.     *hRes = 0;
  3614.     *vRes = 0;
  3615.  
  3616.     outputPrinter = GXGetJobOutputPrinter(whichJob);
  3617.     numViewDevices = GXCountPrinterViewDevices(outputPrinter);
  3618.  
  3619. /*
  3620.     Loop through the viewdevices that this printer supports,
  3621.     and get the highest "square" (vertical == horizontal)
  3622.     resolution.
  3623. */
  3624.  
  3625.     for (idx = 1; idx <= numViewDevices; idx++)
  3626.     {
  3627.         printerVDev = GXGetPrinterViewDevice(outputPrinter, idx);
  3628.         GXGetViewDeviceMapping(printerVDev, &vDevMapping);
  3629.  
  3630.         if ((vDevMapping.map[0][0] == vDevMapping.map[1][1]) &&
  3631.             (vDevMapping.map[0][0] > *hRes) && (vDevMapping.map[1][1] > *vRes))
  3632.         {
  3633.             *hRes = vDevMapping.map[0][0];
  3634.             *vRes = vDevMapping.map[1][1];
  3635.         }
  3636.     }
  3637.  
  3638. /*
  3639.     We have only scaling factors (multiples of 72 dpi),
  3640.     so convert them into resolutions.
  3641. */
  3642.  
  3643.     *hRes = FixedMultiply(*hRes, ff(72));
  3644.     *vRes = FixedMultiply(*vRes, ff(72));
  3645. }
  3646.  
  3647.  
  3648. // This routine returns the name of the paperType
  3649. // used by the current page of a document.
  3650.  
  3651. OSErr MyGetPaperTypeName(MyDocumentPtr myDocument, Str255 paperTypeName)
  3652. {
  3653.     gxPaperType        thePaperType;
  3654.     long            curPage;
  3655.     gxFormat        pgFormat;
  3656.  
  3657. // Get the format for the current page.  If the format is nil,
  3658. // this indicates that we should use the job's default format.
  3659.  
  3660.     curPage = myDocument->curPage;
  3661.     pgFormat = myDocument->pageFormat[curPage -1];
  3662.     
  3663.     if (pgFormat == nil)
  3664.         pgFormat = GXGetJobFormat(myDocument->documentJob, 1);
  3665.  
  3666. // Get the format's paperType and the paperType's name.
  3667.  
  3668.     thePaperType = GXGetFormatPaperType(pgFormat);
  3669.     GXGetPaperTypeName(thePaperType, paperTypeName);
  3670.  
  3671.     return GXGetJobError(myDocument->documentJob);
  3672. }
  3673.  
  3674.  
  3675. // This routine returns the dimensions of the page and
  3676. // paper areas of the paperType used by the current
  3677. // page of a document.
  3678.  
  3679. OSErr MyGetPaperTypeDims(MyDocumentPtr myDocument,
  3680.                          gxRectangle *pageBounds, gxRectangle *paperBounds)
  3681. {
  3682.     gxPaperType        thePaperType;
  3683.     long            curPage;
  3684.     gxFormat        pgFormat;
  3685.  
  3686. // Get the format for the current page.  If the format is nil,
  3687. // this indicates that we should use the job's default format.
  3688.  
  3689.     curPage = myDocument->curPage;
  3690.     pgFormat = myDocument->pageFormat[curPage -1];
  3691.     
  3692.     if (pgFormat == nil)
  3693.         pgFormat = GXGetJobFormat(myDocument->documentJob, 1);
  3694.  
  3695. // Get the format's paperType and the paperType's bounds.
  3696. // Note that you could also use GXGetFormatDimensions to do this.
  3697.  
  3698.     thePaperType = GXGetFormatPaperType(pgFormat);
  3699.     GXGetPaperTypeDimensions(thePaperType, pageBounds, paperBounds);
  3700.  
  3701.     return GXGetJobError(myDocument->documentJob);
  3702. }
  3703.  
  3704.  
  3705. // This routine displays information about every
  3706. // paperType in a document's job which can be
  3707. // used on the document's current output device.
  3708.  
  3709. OSErr MyListAllPaperTypes(MyDocumentPtr myDocument)
  3710. {
  3711.     GXForEachJobPaperTypeDo(myDocument->documentJob, (gxPaperTypeProc) MyPTInfoProc, nil, false);
  3712.     return GXGetJobError(myDocument->documentJob);
  3713. }
  3714.  
  3715.  
  3716. // This routine is a paperType procedure.  It displays
  3717. // the name and dimensions of the paperType passed.
  3718.  
  3719. pascal gxLoopStatus MyPTInfoProc(gxPaperType thePaperType, void *refCon)
  3720. {
  3721.     gxRectangle        pageBounds, paperBounds;
  3722.     Str255            pStr1, pStr2;
  3723.     char            *pStr1Ptr;
  3724.  
  3725. #pragma unused(refCon);
  3726.  
  3727. // Get the paperType's name.
  3728.  
  3729.     GXGetPaperTypeName(thePaperType, pStr1);
  3730.     pStr1[pStr1[pStr1[0]]] = 0;
  3731.     pStr1Ptr = (char *) &pStr1[1];
  3732.  
  3733.  
  3734. // Get the paperType's dimensions.
  3735.  
  3736.     GXGetPaperTypeDimensions(thePaperType, &pageBounds, &paperBounds);
  3737.     pStr2[0] = sprintf((char *) &pStr2[1], "%s: %s %i, %i, %i, %i.  %s %i, %i, %i, %i.",
  3738.                       pStr1Ptr,
  3739.                       "\npageBounds =",
  3740.                       pageBounds.top >>16,
  3741.                       pageBounds.left >>16,
  3742.                       pageBounds.bottom >>16,
  3743.                       pageBounds.right >>16,
  3744.                       "\npaperBounds =",
  3745.                       paperBounds.top >>16,
  3746.                       paperBounds.left >>16,
  3747.                       paperBounds.bottom >>16,
  3748.                       paperBounds.right >>16);
  3749.  
  3750.     MyDisplayInfo(pStr2);
  3751.  
  3752. // Keep looping until all papertypes have been accessed.
  3753.  
  3754.     return gxKeepLooping;
  3755. }
  3756.  
  3757.  
  3758. // This routine displays an "About…" dialog.
  3759.  
  3760. void MyDisplayAbout()
  3761. {
  3762.     short        oldResFile, theItem;
  3763.     DialogPtr    theDialog;
  3764.     GrafPtr        oldPort;
  3765.  
  3766.     oldResFile = CurResFile();
  3767.     UseResFile(gAppResRefNum);
  3768.  
  3769.     theDialog = GetNewDialog(r_aboutDlog, nil, (WindowPtr) -1);
  3770.     
  3771.     if (theDialog)
  3772.     {
  3773.         GetPort(&oldPort);
  3774.         SetPort(theDialog);
  3775.         MyPositionWindow(theDialog, true, n_dlogLevel);
  3776.     
  3777.         do
  3778.         {
  3779.             ModalDialog(nil, &theItem);
  3780.         }
  3781.         while (theItem != kOKButton);
  3782.  
  3783.         SetPort(oldPort);
  3784.         DisposeDialog(theDialog);
  3785.     }
  3786.     
  3787.     UseResFile(oldResFile);
  3788. }
  3789.  
  3790.  
  3791. // This routine displays a dialog with a message and an "OK"
  3792. // button in it.  When the user clicks OK, the dialog is disposed.
  3793. // We use this routine to show information to the user using a
  3794. // means more friendly than the DebugStr calls we used to make.
  3795.  
  3796. void MyDisplayInfo(Str255 msg)
  3797. {
  3798.     short        oldResFile, itemType, theItem;
  3799.     Handle        itemHdl;
  3800.     Rect        itemRect;
  3801.     DialogPtr    theDialog;
  3802.     GrafPtr        oldPort;
  3803.  
  3804.     oldResFile = CurResFile();
  3805.     UseResFile(gAppResRefNum);
  3806.  
  3807.     theDialog = GetNewDialog(r_msgDlog, nil, (WindowPtr) -1);
  3808.     
  3809.     if (theDialog)
  3810.     {
  3811.         GetPort(&oldPort);
  3812.         SetPort(theDialog);
  3813.         
  3814.         GetDItem(theDialog, d_msgItem, &itemType, &itemHdl, &itemRect);
  3815.         SetIText(itemHdl, msg);
  3816.         MyPositionWindow(theDialog, true, n_dlogLevel);
  3817.     
  3818.         do
  3819.         {
  3820.             ModalDialog(nil, &theItem);
  3821.         }
  3822.         while (theItem != kOKButton);
  3823.  
  3824.         SetPort(oldPort);
  3825.         DisposeDialog(theDialog);
  3826.     }
  3827.     
  3828.     UseResFile(oldResFile);
  3829. }
  3830.  
  3831.  
  3832. // This routine positions a window on the screen, centered
  3833. // horizontally and positioned vertPercent down the current
  3834. // screen.  If showIt is true, we make the window visible,
  3835. // otherwise we hide it.
  3836.  
  3837. void MyPositionWindow(WindowPtr windPtr, Boolean showIt, float vertPercent)
  3838. {
  3839.     Rect        devRect;
  3840.     short        amtFromTop, windWidth, deviceWidth;
  3841.     GDHandle    curGDH;
  3842.  
  3843. // Get the current GDevice and use its bounds to calculate where we
  3844. // should move the window to.
  3845.  
  3846.     if (windPtr != nil)
  3847.     {
  3848.         curGDH = GetGDevice();
  3849.         devRect = (*curGDH)->gdRect;
  3850.  
  3851.         amtFromTop = (devRect.bottom - devRect.top +1) * vertPercent;
  3852.         windWidth = windPtr->portRect.right - windPtr->portRect.left +1;
  3853.         deviceWidth = devRect.right - devRect.left +1;
  3854.  
  3855.  
  3856. // Hide the window, move it, and (if we're supposed to) show it again.
  3857.  
  3858.         ShowHide(windPtr, false);
  3859.         MoveWindow(windPtr, devRect.left + (deviceWidth /2 - windWidth /2), devRect.top + amtFromTop, true);
  3860.         if (showIt) ShowHide(windPtr, true);
  3861.     }
  3862. }
  3863.  
  3864.  
  3865. //------  main  -------------------------------------------------------------
  3866.  
  3867. main()
  3868. {
  3869.     OSErr                err;
  3870.     gxGraphicsClient    client;
  3871.     short                 i;
  3872.  
  3873.     MaxApplZone();
  3874.     for (i=1; i<=4; i++) MoreMasters();
  3875.  
  3876.     client = GXNewGraphicsClient(0, 400 * 1024, 0);
  3877.     err = MyInitializeApp();
  3878.  
  3879.     GXEnterGraphics();
  3880.     err = GXInitPrinting();
  3881.  
  3882.     if (!err) MyEventLoop();
  3883.         
  3884.     err = GXExitPrinting();
  3885.     GXExitGraphics();
  3886.     GXDisposeGraphicsClient(client);
  3887. }
  3888.